Spring 的 DAO 支持
Spring 提供許多工具類用于對 DAO 實(shí)現(xiàn)簡化開發(fā)步驟
Spring 提供了一致的異常抽象协怒,將原有的 Checked 異常轉(zhuǎn)換包裝為 Runtime 異常邮绿,因而勘究,編碼時(shí)無序捕獲各種技術(shù)中特定的異常
-
HibernateTemplate
public class PersonDaoImpl implements PersonDao { private HibernateTemplate ht = null; @Resource(name="sessionFactory") protected SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } private HibernateTemplate getHibernateTemplate() { if (ht == null) { ht = new HibernateTemplate(sessionFactory); } return ht; } // HibernateTemplate 的使用類似于 Session + Query public Person get(Integer id) { return getHibernateTemplate().get(Person.class, id); } }
缺點(diǎn):靈活性不足鹃答,不能用 Hibernate API 進(jìn)行持久化訪問
-
HibernateCallback 接口
- HibernateTemplate 的
.execute(HibernateCallback action)
和.executeFind(HibernateCallback action)
方法接收一個(gè) HibernateCallback 接口的實(shí)現(xiàn) - HibernateCallback 接口包含
doInHibernate(Session session)
方法 - 兩者結(jié)合可解決靈活應(yīng)用 Hibernate API 的問題
public class PersonDaoImpl implements PersonDao { private HibernateTemplate ht = null; @Resource(name="sessionFactory") protected SessionFactory sessionFactory; public SessionFactory getSessionFactory() { return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } private HibernateTemplate getHibernateTemplate() { if (ht == null) { ht = new HibernateTemplate(sessionFactory); } return ht; } public Person get(final Integer id) { return getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { return session.get(Person.class, id); } }); } }
- HibernateTemplate 的
-
HibernateDaoSupport
- HibernateDaoSupport 的
getHibernateTemplate()
方法返回 HibernateTemplate 對象 - HibernateDaoSupport 的
setSessionFactory(SessionFactory sessionFactory)
可用于接收 Spring 的依賴注入,從而允許使用 sessionFactory 對象 - HibernateDaoSupport 的 DAO 實(shí)現(xiàn)由 HibernateTemplate 對象完成
- DAO 類的實(shí)現(xiàn)繼承 HibernateDaoSupport
- HibernateDaoSupport 的
Spring 使用聲明式事務(wù)
- Spring 使用聲明式事務(wù)來進(jìn)行統(tǒng)一的事務(wù)管理
- 只需要在配置文件中增加事務(wù)控制片段,業(yè)務(wù)邏輯組件的方法將會有事務(wù)性
- Spring 的聲明式事務(wù)支持在不同事務(wù)策略之間自由切換
配置 applicationContext.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd>
<description>Spring公共配置</description>
<!-- 自動掃描與裝配bean -->
<context:component-scan base-package="com.lian" />
<!-- 導(dǎo)入外部的 properties 文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置 dataSource 和 sessionFactory -->
<!-- 配置事務(wù) -->
</beans>
配置 dataSource 和 sessionFactory
- 直接在 spring 的配置文件 applicationContext.xml 中配置
<!-- 配置c3p0數(shù)據(jù)庫連接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 數(shù)據(jù)連接信息 --> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <!-- 其他配置 --> <!--初始化時(shí)獲取三個(gè)連接鳖眼,取值應(yīng)在minPoolSize與maxPoolSize之間。Default: 3 --> <property name="initialPoolSize" value="3"></property> <!--連接池中保留的最小連接數(shù)嚼摩。Default: 3 --> <property name="minPoolSize" value="3"></property> <!--連接池中保留的最大連接數(shù)钦讳。Default: 15 --> <property name="maxPoolSize" value="5"></property> <!--當(dāng)連接池中的連接耗盡的時(shí)候c3p0一次同時(shí)獲取的連接數(shù)。Default: 3 --> <property name="acquireIncrement" value="3"></property> <!-- 控制數(shù)據(jù)源內(nèi)加載的PreparedStatements數(shù)量枕面。如果maxStatements與maxStatementsPerConnection均為0蜂厅,則緩存被關(guān)閉。Default: 0 --> <property name="maxStatements" value="8"></property> <!--maxStatementsPerConnection定義了連接池內(nèi)單個(gè)連接所擁有的最大緩存statements數(shù)膊畴。Default: 0 --> <property name="maxStatementsPerConnection" value="5"></property> <!--最大空閑時(shí)間,1800秒內(nèi)未使用則連接被丟棄掘猿。若為0則永不丟棄。Default: 0 --> <property name="maxIdleTime" value="1800"></property> </bean> <!-- 配置 sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- 設(shè)置 dataSource 屬性 --> <property name="dataSource" ref="dataSource"></property> <!-- 配置 Hibernate Properties --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hbm2ddl.auto">update</prop> </props> </property> <!-- 配置 Mapping Resources --> <property name="mappingLocations" value="classpath:com/lian/entity/*.hbm.xml"></property> </bean>
- 引用 Hibernate 的配置文件 hibernate.cfg.xml
<!-- 配置 sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- 引用 Hibernate 的配置文件來配置 dataSource 和 Hibernate Properties --> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> <!-- 配置 Mapping Resources --> <property name="mappingLocations" value="classpath:com/lian/entity/*.hbm.xml"></property> </bean>
當(dāng)相同的配置項(xiàng)都存在時(shí)唇跨,applicationContext.xml 中的優(yōu)先級高于 hibernate.cfg.xml
配置事務(wù)
-
XML 配置
<!-- 配置 局部事務(wù)管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 配置 增強(qiáng)事務(wù) Bean --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置 詳細(xì)的事務(wù)語義 --> <tx:attributes> <!-- 為不同的方法指定相應(yīng)的事務(wù)語義 --> <!-- 所有以 get 開頭的方法都是 read-only 的 --> <tx:method name="get*" read-only="true"/> <!-- 其他方法使用默認(rèn)的事務(wù)設(shè)置 --> <tx:method name="*"> </tx:attributes> </tx:advice> <aop:config> <!-- 配置一個(gè)切入點(diǎn) --> <aop:pointcut id="onePointcut" expression="bean(personService)"/> <!-- 指定在 onePointcut 切入點(diǎn)應(yīng)用 txAdvice 事務(wù)增強(qiáng)處理 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="onePointcut"/> </aop:config>
-
Annotation
<!-- 配置 局部事務(wù)管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 根據(jù) Annotation 生成事務(wù)代理 --> <tx:annotation-driven transaction-manager="transactionManager"/>
-
@Transactional(...)
屬性 說明 name 當(dāng)在配置文件中有多個(gè) TransactionManager , 可以用該屬性指定選擇哪個(gè)事務(wù)管理器 propagation 事務(wù)的傳播行為稠通,默認(rèn)值為 REQUIRED isolation 事務(wù)的隔離度,默認(rèn)值采用 DEFAULT timeout 事務(wù)的超時(shí)時(shí)間买猖,默認(rèn)值為-1改橘。如果超過該時(shí)間限制但事務(wù)還沒有完成,則自動回滾事務(wù) read-only 指定事務(wù)是否為只讀事務(wù)玉控,默認(rèn)值為 false飞主;為了忽略那些不需要事務(wù)的方法,比如讀取數(shù)據(jù)高诺,可以設(shè)置 read-only 為 true rollback-for 用于指定能夠觸發(fā)事務(wù)回滾的異常類型碌识,如果有多個(gè)異常類型需要指定,各類型之間可以通過逗號分隔 no-rollback- for 拋出 no-rollback-for 指定的異常類型虱而,不回滾事務(wù)
-
透徹的掌握 Spring 中@transactional 的使用
Hibernate 框架下的通用 DAO 層
BaseDao.java
/**
* 通用泛型DAO
*/
public interface BaseDao<T> {
/**
* 新增一個(gè)實(shí)例
* @param entity 要新增的實(shí)例
*/
public void save(T entity);
/**
* 根據(jù)主鍵刪除一個(gè)實(shí)例
* @param id 主鍵
*/
public void delete(int id);
/**
* 編輯指定實(shí)例的詳細(xì)信息
* @param entity 實(shí)例
*/
public void edit(T entity);
/**
* 根據(jù)主鍵獲取對應(yīng)的實(shí)例
* @param id 主鍵值
* @return 如果查詢成功筏餐,返回符合條件的實(shí)例;如果查詢失敗,返回null
*/
public T get(Integer id);
/**
* 根據(jù)主鍵獲取對應(yīng)的實(shí)例
* @param id 主鍵值
* @return 如果查詢成功牡拇,返回符合條件的實(shí)例;如果查詢失敗魁瞪,拋出空指針異常
*/
public T load(Integer id);
/**
* 獲取所有實(shí)體實(shí)例列表
* @return 符合條件的實(shí)例列表
*/
public List<T> findAll();
/**
* 統(tǒng)計(jì)總實(shí)體實(shí)例的數(shù)量
* @return 總數(shù)量
*/
public int totalCount();
/**
* 獲取分頁列表
* @param pageNo 當(dāng)前頁號
* @param pageSize 每頁要顯示的記錄數(shù)
* @return 符合分頁條件的分頁模型實(shí)例
*/
public PageModel<T> findByPager(int pageNo, int pageSize);
/**
* 根據(jù)指定的SQL語句和參數(shù)值執(zhí)行更新數(shù)據(jù)的操作
* @param sql SQL語句
* @param paramValues 參數(shù)值數(shù)組
*/
public void update(String sql);
/**
* 根據(jù)指定的SQL語句和參數(shù)值執(zhí)行單個(gè)對象的查詢操作
* @param sql SQL語句
* @param paramValues 參數(shù)值
* @return 符合條件的實(shí)體對象
*/
public T findUnique(String sql);
}
BaseDaoImpl.java
/**
* 通用DAO接口的實(shí)現(xiàn)類
*/
@SuppressWarnings("unchecked")
public class BaseDaoImpl<T> implements BaseDao<T> {
/**
* 對應(yīng)的持久化類
*/
private Class<T> clazz;
@Resource(name="sessionFactory")
protected SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public BaseDaoImpl(){
//通過反射機(jī)制獲取子類傳遞過來的實(shí)體類的類型信息
ParameterizedType type=(ParameterizedType)this.getClass().getGenericSuperclass();
this.clazz=(Class<T>)type.getActualTypeArguments()[0];
}
@Override
public void save(T entity) {
Session session = sessionFactory.getCurrentSession();
session.save(entity);
}
@Override
public void delete(int id) {
Session session = sessionFactory.getCurrentSession();
session.delete(get(id));
}
@Override
public void edit(T entity) {
Session session = sessionFactory.getCurrentSession();
session.merge(entity);
}
@Override
public T get(Integer id) {
Session session = sessionFactory.getCurrentSession();
return (T) session.get(clazz, id);
}
@Override
public T load(Integer id) {
Session session = sessionFactory.getCurrentSession();
return (T)session.load(clazz, id);
}
@Override
public List<T> findAll() {
Session session = sessionFactory.getCurrentSession();
String hql = "select t from "+clazz.getSimpleName()+" t";
return (List<T>)session.createQuery(hql).list();
}
@Override
public int totalCount() {
Session session = sessionFactory.getCurrentSession();
int count = 0;
String hql = "select count(t) from "+clazz.getSimpleName()+" t";
Long temp = (Long)session.createQuery(hql).uniqueResult();
if(temp != null){
count = temp.intValue();
}
return count;
}
@Override
public PageModel<T> findByPager(int pageNo, int pageSize) {
Session session = sessionFactory.getCurrentSession();
PageModel<T> pm = new PageModel<T>(pageNo, pageSize);
String hql = "select t from "+clazz.getSimpleName()+" t";
int startRow = (pageNo - 1) * pageSize;
pm.setDatas(session.createQuery(hql).setFirstResult(startRow).setMaxResults(pageSize).list());
pm.setRecordCount(totalCount());
return pm;
}
@Override
public void update(String hql) {
Session session = sessionFactory.getCurrentSession();
session.createQuery(hql);
}
@Override
public T findUnique(String hql) {
Session session = sessionFactory.getCurrentSession();
return (T)session.createQuery(hql).uniqueResult();
}
}
PageModel.java
/**
* 分頁模型類
*/
public class PageModel<T> {
//當(dāng)前頁號
private int pageNo=1;
//每頁顯示的記錄數(shù)
private int pageSize=10;
//總記錄數(shù)
private int recordCount;
//總頁數(shù)
private int pageCount;
//存放分頁數(shù)據(jù)的集合
private List<T> datas;
public PageModel(){
}
public PageModel(int pageNo,int pageSize){
this.pageNo=pageNo;
this.pageSize=pageSize;
}
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getRecordCount() {
return recordCount;
}
public void setRecordCount(int recordCount) {
this.recordCount = recordCount;
}
public int getPageCount() {
if(this.getRecordCount()<=0){
return 0;
}else{
pageCount=(recordCount+pageSize-1)/pageSize;
}
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public List<T> getDatas() {
return datas;
}
public void setDatas(List<T> datas) {
this.datas = datas;
}
}