1.Spring提供的dao支持:
DAO模式是標(biāo)準(zhǔn)的java EE設(shè)計(jì)模式,DAO模式的核心思想是所有的數(shù)據(jù)庫訪問,都通過DAO組件完成,DAO組件封裝了數(shù)據(jù)庫的增刪改查等原子操作,業(yè)務(wù)邏輯組件依賴DAO組件提供的原子操作,對于javaEE的應(yīng)用架構(gòu),有非常多的,不管細(xì)節(jié)如何變化,javaEE大致 可以分為如下三層:
<li>表現(xiàn)層;
<li>業(yè)務(wù)邏輯層;
<li>數(shù)據(jù)持久層;
Spring提供了一系列的抽象類,這些抽象類將被作為應(yīng)用中DAO組件可以通過這些抽象類,Spring簡化了DAO的開發(fā)步驟,能夠以一致的訪問方式使用數(shù)據(jù)庫訪問技術(shù),不管底層采用JDBC、JDO還是個(gè)Hibernate,應(yīng)用中都采用一致的編程模型。
Spring提供的多種數(shù)據(jù)庫訪問技術(shù)的DAO支持,包括Hibernate、JDO、TopLink、iBatis、OJB、JPA等,就Hibernate的持久層訪問技術(shù)而言,Spring提供如下3個(gè)工具類來支持DAO組件的實(shí)現(xiàn):HibernateDaoSupport、HibernateTemplate、HibernateCallback。
2.管理Hibernate的SessionFactory:
面介紹的Hibernate的時(shí)候知道:通過Hibernate進(jìn)行持久層訪問的時(shí)候,Hibernate的SessionFactory是非常重要的對象,它是單個(gè)數(shù)據(jù)庫映射關(guān)系編譯后的內(nèi)存鏡像,大部分情況下,一個(gè)java EE應(yīng)用對應(yīng)一個(gè)數(shù)據(jù)庫,即對應(yīng)一個(gè)SessionFactory對象。
配置SessionFactory的示范代碼:
<!-- 定義數(shù)據(jù)源Bean,使用C3P0數(shù)據(jù)源實(shí)現(xiàn) -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 指定連接數(shù)據(jù)庫的驅(qū)動(dòng) -->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<!-- 指定連接數(shù)據(jù)庫的URL -->
<property name="jdbcUrl" value="jdbc:mysql://localhost/javaee"/>
<!-- 指定連接數(shù)據(jù)庫的用戶名 -->
<property name="user" value="root"/>
<!-- 指定連接數(shù)據(jù)庫的密碼 -->
<property name="password" value="32147"/>
<!-- 指定連接數(shù)據(jù)庫連接池的最大連接數(shù) -->
<property name="maxPoolSize" value="40"/>
<!-- 指定連接數(shù)據(jù)庫連接池的最小連接數(shù) -->
<property name="minPoolSize" value="1"/>
<!-- 指定連接數(shù)據(jù)庫連接池的初始化連接數(shù) -->
<property name="initialPoolSize" value="1"/>
<!-- 指定連接數(shù)據(jù)庫連接池的連接的最大空閑時(shí)間 -->
<property name="maxIdleTime" value="20"/>
</bean>
<!-- 定義Hibernate的SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 依賴注入數(shù)據(jù)源,注入正是上面定義的dataSource -->
<property name="dataSource" ref="dataSource"/>
<!-- mappingResouces屬性用來列出全部映射文件 -->
<property name="mappingResources">
<list>
<!-- 以下用來列出Hibernate映射文件 -->
<value>Person.hbm.xml</value>
</list>
</property>
<!-- 定義Hibernate的SessionFactory的屬性 -->
<property name="hibernateProperties">
<props>
<!-- 指定數(shù)據(jù)庫方言 -->
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect</prop>
<!-- 是否根據(jù)需要每次自動(dòng)創(chuàng)建數(shù)據(jù)庫 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!-- 顯示Hibernate持久化操作所生成的SQL -->
<prop key="hibernate.show_sql">true</prop>
<!-- 將SQL腳本進(jìn)行格式化后再輸出 -->
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
3.使用HibernateTemplate:
HibernateTemplate提供持久層訪問模版化,它只需要提供一個(gè)SessionFactory的引用,SessionFactory可以通過構(gòu)造方法參數(shù)傳入,也可以通過設(shè)值方式傳入。
示例:
public class PersonDaoImpl implements PersonDao
{
//定義一個(gè)HibernateTemplate對象,用于執(zhí)行持久化操作
private HibernateTemplate ht = null;
//Hibernate持久化操作所需的SessionFactory
private SessionFactory sessionFactory;
//依賴注入SessionFactory的setter方法
public void setSessionFactory(SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
//初始化HibernateTemplate的方法
private HibernateTemplate getHibernateTemplate()
{
if (ht == null)
{
ht = new HibernateTemplate(sessionFactory);
}
return ht;
}
/**
* 加載Person實(shí)例
* @param id 需要加載的Person實(shí)例的標(biāo)識屬性值
* @return 指定id對應(yīng)的Person實(shí)例
*/
public Person get(Integer id)
{
return (Person)getHibernateTemplate()
.get(Person.class, id);
}
/**
* 保存Person實(shí)例
* @param person 需要保存的Person實(shí)例
* @return 剛剛保存的Person實(shí)例的標(biāo)識屬性值
*/
public Integer save(Person person)
{
return (Integer)getHibernateTemplate()
.save(person);
}
/**
* 修改Person實(shí)例
* @param person 需要修改的Person實(shí)例
*/
public void update(Person person)
{
getHibernateTemplate().update(person);
}
/**
* 刪除Person實(shí)例
* @param id 需要?jiǎng)h除的Person實(shí)例的標(biāo)識屬性值
*/
public void delete(Integer id)
{
getHibernateTemplate().delete(get(id));
}
/**
* 刪除Person實(shí)例
* @param person 需要?jiǎng)h除的Person實(shí)例
*/
public void delete(Person person)
{
getHibernateTemplate().delete(person);
}
/**
* 根據(jù)用戶名查找Person
* @param name 查詢的人名
* @return 指定用戶名對應(yīng)的全部Person
*/
public List<Person> findByName(String name)
{
return (List<Person>)getHibernateTemplate()
.find("from Person p where p.name like ?" , name);
}
/**
* 查詢?nèi)縋erson實(shí)例
* @return 全部Person實(shí)例
*/
public List findAllPerson()
{
return (List<Person>)getHibernateTemplate()
.find("from Person");
}
/**
* 查詢數(shù)據(jù)表中Person實(shí)例的總數(shù)
* @return 數(shù)據(jù)表中Person實(shí)例的總數(shù)
*/
public long getPersonNumber()
{
return (Long)getHibernateTemplate().find
("select count(*) from Person as p")
.get(0);
}
}
4.使用HibernateCallback:
HibernateTemplate還提供一種更加靈活的方式來操作數(shù)據(jù)庫,,通過這種方式可以完全使用Hibernate的操作方式,HibernateTemplate的靈活方式是通過如下兩個(gè)方法來完成的。
Object execute(HibernateCallback action);
List executeFind(HibernateCallback action);
這兩個(gè)方法都需要一個(gè)HibernateCallback實(shí)例,HibernateCallback是一個(gè)接口,該接口包含一個(gè)方法doInHibernate(org.hibernate Session session),該方法是有一個(gè)Session參數(shù),當(dāng)我們在開發(fā)中提供HibernateCallback實(shí)現(xiàn)類時(shí),必須實(shí)現(xiàn)接口里的doInHibernate方法,該方法體內(nèi)即可獲得 Hibernate Session的引用。一旦獲取到Session的引用我們就可以完全以Hibernate的方式進(jìn)行數(shù)據(jù)庫的訪問。
示例:
public class YeekuHibernateDaoSupport extends HibernateDaoSupport
{
/**
* 使用hql語句進(jìn)行分頁查詢
* @param hql 需要查詢的hql語句
* @param offset 第一條記錄索引
* @param pageSize 每頁需要顯示的記錄數(shù)
* @return 當(dāng)前頁的所有記錄
*/
public List findByPage(final String hql,
final int offset, final int pageSize)
{
//通過一個(gè)HibernateCallback對象來執(zhí)行查詢
List list = getHibernateTemplate()
.executeFind(new HibernateCallback()
{
//實(shí)現(xiàn)HibernateCallback接口必須實(shí)現(xiàn)的方法
public Object doInHibernate(Session session)
throws HibernateException, SQLException
{
//執(zhí)行Hibernate分頁查詢
List result = session.createQuery(hql)
.setFirstResult(offset)
.setMaxResults(pageSize)
.list();
return result;
}
});
return list;
}
/**
* 使用hql語句進(jìn)行分頁查詢
* @param hql 需要查詢的hql語句
* @param value 如果hql有一個(gè)參數(shù)需要傳入,value就是傳入hql語句的參數(shù)
* @param offset 第一條記錄索引
* @param pageSize 每頁需要顯示的記錄數(shù)
* @return 當(dāng)前頁的所有記錄
*/
public List findByPage(final String hql , final Object value ,
final int offset, final int pageSize)
{
//通過一個(gè)HibernateCallback對象來執(zhí)行查詢
List list = getHibernateTemplate()
.executeFind(new HibernateCallback()
{
//實(shí)現(xiàn)HibernateCallback接口必須實(shí)現(xiàn)的方法
public Object doInHibernate(Session session)
throws HibernateException, SQLException
{
//執(zhí)行Hibernate分頁查詢
List result = session.createQuery(hql)
//為hql語句傳入?yún)?shù)
.setParameter(0, value)
.setFirstResult(offset)
.setMaxResults(pageSize)
.list();
return result;
}
});
return list;
}
/**
* 使用hql語句進(jìn)行分頁查詢
* @param hql 需要查詢的hql語句
* @param values 如果hql有多個(gè)個(gè)參數(shù)需要傳入,values就是傳入hql的參數(shù)數(shù)組
* @param offset 第一條記錄索引
* @param pageSize 每頁需要顯示的記錄數(shù)
* @return 當(dāng)前頁的所有記錄
*/
public List findByPage(final String hql, final Object[] values,
final int offset, final int pageSize)
{
//通過一個(gè)HibernateCallback對象來執(zhí)行查詢
List list = getHibernateTemplate()
.executeFind(new HibernateCallback()
{
//實(shí)現(xiàn)HibernateCallback接口必須實(shí)現(xiàn)的方法
public Object doInHibernate(Session session)
throws HibernateException, SQLException
{
//執(zhí)行Hibernate分頁查詢
Query query = session.createQuery(hql);
//為hql語句傳入?yún)?shù)
for (int i = 0 ; i < values.length ; i++)
{
query.setParameter( i, values[i]);
}
List result = query.setFirstResult(offset)
.setMaxResults(pageSize)
.list();
return result;
}
});
return list;
}
}
Spring提供了XxxTemplate和XxxCallback互為補(bǔ)充,XxxTemplate對操作進(jìn)行封裝,XxxCallback解決了封裝后靈活性不足的缺陷。
5.實(shí)現(xiàn)DAO組件:
為了實(shí)現(xiàn)DAO組件,Spring提供了大量的XxxDaoSupport類,這些dao支持類已經(jīng)完成了大量基礎(chǔ)性的工作。
Spring為Hibernate的DAO提供工具類:HibernateDaoSupport,該類主要提供如下幾個(gè)方法來簡化DAO的實(shí)現(xiàn):
public final HibernateTemplate getHibernateTemplate ();
public final void setSessionFactory(SessionFactory sessionFactory);
setSessionFactory方法可用于接收Spring的依賴注入,允許使用依賴注入Spring 管理的SessionFactory實(shí)例。
public class PersonDaoHibernate
extends HibernateDaoSupport implements PersonDao
{
/**
* 加載Person實(shí)例
* @param id 需要加載的Person實(shí)例的標(biāo)識屬性值
* @return 指定id對應(yīng)的Person實(shí)例
*/
public Person get(Integer id)
{
return (Person)getHibernateTemplate()
.get(Person.class, id);
}
/**
* 保存Person實(shí)例
* @param person 需要保存的Person實(shí)例
* @return 剛剛保存的Person實(shí)例的標(biāo)識屬性值
*/
public Integer save(Person person)
{
return (Integer)getHibernateTemplate()
.save(person);
}
/**
* 修改Person實(shí)例
* @param person 需要修改的Person實(shí)例
*/
public void update(Person person)
{
getHibernateTemplate().update(person);
}
/**
* 刪除Person實(shí)例
* @param id 需要?jiǎng)h除的Person實(shí)例的標(biāo)識屬性值
*/
public void delete(Integer id)
{
getHibernateTemplate().delete(get(id));
}
/**
* 刪除Person實(shí)例
* @param person 需要?jiǎng)h除的Person實(shí)例
*/
public void delete(Person person)
{
getHibernateTemplate().delete(person);
}
/**
* 根據(jù)用戶名查找Person
* @param name 查詢的人名
* @return 指定用戶名對應(yīng)的全部Person
*/
public List<Person> findByName(String name)
{
return (List<Person>)getHibernateTemplate()
.find("from Person p where p.name like ?" , name);
}
/**
* 查詢?nèi)縋erson實(shí)例
* @return 全部Person實(shí)例
*/
public List findAllPerson()
{
return (List<Person>)getHibernateTemplate()
.find("from Person");
}
}
實(shí)際上,DAO的實(shí)現(xiàn)依然借助于HibernateTemplate的模板訪問方式,只是HibernateDaoSupport提供了兩個(gè)工具方法。
至此Java EE應(yīng)用所需的各種組件都已經(jīng)出現(xiàn)了。
從用戶的角度上看,用戶發(fā)出HTTP請求,當(dāng)MVC框架的控制器組件攔截到用戶的請求,將調(diào)用系統(tǒng)的業(yè)務(wù)邏輯組件,業(yè)務(wù)邏輯組件則調(diào)用 系統(tǒng)的DAO組件,,而DAO組件則依賴于SessionFactory和DataSOurce等底層的實(shí)現(xiàn)數(shù)據(jù)庫訪問。
從系統(tǒng)的實(shí)現(xiàn)角度上看,IoC容器先創(chuàng)建SessionFactory和DataSource等底層組件,然后將這些組件注入DAO組件,提供一個(gè)完整的Dao組件,并將DAO組件注入給業(yè)務(wù)邏輯組件,從而提供一個(gè)完整的業(yè)務(wù)邏輯組件,而業(yè)務(wù)邏輯組件又被注入給控制器組件,控制器組件負(fù)責(zé)攔截用戶請求,并將處理結(jié)果呈現(xiàn)給用戶。