spring 封裝了hibernate dao的操作:學習中遇到的問題,以及自己的見解
一、使用了由spring框架提供的對hibernate3的封裝。這樣做無非是爲了使用spring提供的對事務的統一管理。當我們用到由spring所封裝的hibernate的時候一定會用到一個類:HibernateTemplate.這是一個對持久層處理封裝的非常完整的類,包括對session的管理(事實上session的獲取於釋放是一個令人頭疼的問題)等等,我們通常會使用HibernateTemplate的excute方法來進行數據庫操作(即使我們調用的也許是別的類似於find、get之類的方法,但是實質上最終還是轉變爲了調用excute方法)。
1.這裏採用的方法:HibernateBaseDao (自定義一個類)
/**
*package org.springframework.orm.hibernate3.support.HibernateDaoSupport;
*HibernateDaoSupport是spring中的類
*/
HibernateBaseDao extends HibernateDaoSupport{
這中間是一系列實現的對數據庫的crud操作
public void executeBatchUpdate(final List sqls) {
//new HibernateDaoSupport().
getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
try{
Connection con = session.connection();
Statement st = con.createStatement();
for (int i = 0; i < sqls.size(); i++) {
String sql= (String) sqls.get(i);
st.addBatch( sql );
log.debug("exec sqls["+i+"]"+sql);
}
if(sqls.size()>0)
st.executeBatch();
}catch (SQLException ex) {
ex.printStackTrace();
throw new DataAccessResourceFailureException(ex.getMessage());
}
return null;
}
});
}
------獲取連接-----------
public Connection getJDBCConnection() {
return (Connection)getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
return session.connection();
}
});
}
}
我們系統中的dao實現類daoimpl 中需要用到 用到HibernateBaseDao 中的方法
那麼我們只需要將HibernateBaseDao 的對象通過spring注入到daoimpl中即可
public class BaseDAOImp implements IBaseDAO {
private HibernateBaseDao hibernateBaseDao;
public static Log log = LogFactory.getLog(BaseDAOImp.class);
public void setHibernateBaseDao(HibernateBaseDao hibernateBaseDao) {
this.hibernateBaseDao = hibernateBaseDao;
}
public void saveVo(VO obj) {
//
hibernateBaseDao.saveObject(obj);
}
public void removeVo(VO obj) {
//
hibernateBaseDao.removeObject(obj);
}
-------------------總結-------------
通常這樣操作我們需要給類HibernateBaseDao 注入一個SessionFactory的實例,他的作用就是獲取jdbc連接
<bean id="hibernateBaseDao" class="com.sitech.crmpd.core.dao.HibernateBaseDao">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="chnds" /> //數據源
</property>
<property name="mappingDirectoryLocations">
<list>
<value>/sitech/res/s99899/hbm</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.use_outer_join">false</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
</props>
</property>
</bean>
這裏的疑問:hibernateBaseDao 繼承自HibernateDaoSupport()類而這個類其實是沒有sessionFactory這個屬性的。哪是從哪裏來的這個屬性呢,又是如何注入的呢
通過看源碼發現了注入的方式:
1.HibernateDaoSupport類有
public abstract class HibernateDaoSupport extends DaoSupport {
private HibernateTemplate hibernateTemplate;//屬性
public final void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory); //有了這個方法,那麼它的子類HibernateDaoSupport 也就有了這個方法,spring會調用這個方法進行注入(注入方式:是看是否有這個set方法,如:setSessionFactory),
}
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {//在上面的set方法中會調用這個方法
return new HibernateTemplate(sessionFactory);//這裏調用構造方法
}
public final SessionFactory getSessionFactory() {
return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);//方法
}
)
HibernateTemplate 類:
public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
public HibernateTemplate(SessionFactory sessionFactory) {
setSessionFactory(sessionFactory);//這個方法是調用的父類的方法,如下面所示
afterPropertiesSet();
}
}
HibernateAccessor 類
public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {
protected final Log logger = LogFactory.getLog(getClass());
private SessionFactory sessionFactory;
private Object entityInterceptor;
private SQLExceptionTranslator jdbcExceptionTranslator;
private int flushMode = FLUSH_AUTO;
private String[] filterNames;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
----------------------------------------------------
二、關於回調函數
說明:HibernateCallback是一個接口
public interface HibernateCallback {
Object doInHibernate(Session session) throws HibernateException, SQLException;
}
如:
public Connection getJDBCConnection() {
return (Connection)getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
return session.connection();
}
});
}
這裏使用了回調的方式;
1.HibernateTemplate,內聯類
2.內聯類實現接口HibernateCallback的doInHibernate 方法
3.HibernateTemplate擁有一個參數爲HibernateCallback接口類型的函數execute(HibernateCallback action)方法.
4.調用HibernateTemplate的get方法時,將內聯類傳給了excute方法
5.執行excute方法時,(你調用它)
已取得內聯類,就可以隨時回調它所實現的HibernateCallback接口中的方法了,
這時它反過來調用你的方法(它調用你),這就是回調了.
Javaeye兩個會員的理解,我覺得比較到位.
概括:(
就是調用系統的一個方法,傳進去一個接口的實現類 or 匿名類。
然後系統的方法調用接口申明的方法,並且注入相應的參數 )
這裏Excute方法的參數是一種匿名類的方式。爲什麼要採用匿名類呢(不管怎麼說匿名類看起來總是讓人覺得不舒服)?這個地方是否必須採用匿名類呢?
1、回調:excute方法會回調HibernateCallback類型的doInHibernate方法;
2、匿名類參數:我們爲excute方法提供的參數並不是一個真正創建出來的;
3、動態創建回調方法:
如果不採用匿名類,我們需要做的是爲HibernateCallback創建一個實現類,並且實現doInHibernate方法
但是最要命的問題是doInHibernate方法的實現對於我們的實際需求來說每一次調用可能都是不一樣的(在doInHibernate方法中我們使用session進行數據庫操作,對於不同的業務邏輯,方法實現必定是不一樣的),採用了匿名類我們不用在代碼重創建新的類型,而且可以動態的創建我們所需要的回調函數。
這裏的回調是這樣的
首先是 getHibernateTemplate().execute()-->execute中HibernateCallback .doInHibernate();
實現回調的地方
public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Session session = getSession();
boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateTemplate");
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(session);
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
Object result = action.doInHibernate(sessionToExpose);//這裏實現了回調接口中的方法();
flushIfNecessary(session, existingTransaction);
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (SQLException ex) {
throw convertJdbcAccessException(ex);
}
catch (RuntimeException ex) {
// Callback code threw application exception...
throw ex;
}
finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
disableFilters(session);
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
}
else {
// Never use deferred close for an explicitly new Session.
if (isAlwaysUseNewSession()) {
SessionFactoryUtils.closeSession(session);
}
else {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
}
}
}
}