spring

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());
    }
   }
  }
 }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章