1. 程式人生 > >由openSession、getCurrentSession和HibernateDaoSupport淺談Spring對事物的支援

由openSession、getCurrentSession和HibernateDaoSupport淺談Spring對事物的支援

    Spring和Hibernate的整合的一個要點就是對事務的支援,openSession、getCurrentSession都是程式設計式事務(手動設定事務的提交、回滾)中重要的物件,HibernateDaoSupport則提供了更方便的宣告式事務支援。

    Hibernate中最重要的就是Session物件的引入,它是對jdbc的深度封裝,包括對事務的處理,Session物件通過SessionFactory來管理,openSession和getCurrentSession是管理session的重要的方法。

    openSession和getCurrentSession的根本區別

在於有沒有綁定當前執行緒,所以,使用方法有差異:

* openSession沒有綁定當前執行緒,所以,使用完後必須關閉,

* currentSession和當前執行緒繫結,在事務結束後會自動關閉。

關於事務的邊界和傳播:

     通常情況下事務的邊界需要設定在業務邏輯處理層中,但是,如果在一個業務中涉及到多個業務邏輯層之間的方法,且需要在同一個事務中執行,那麼,這就涉及到了事務的傳播性。

如果使用openSession,就要在dao層的方法中傳遞session,而這種做法是很糟糕的,首先增加了引數的個數,另外,方法是否需要事務,完全是可以當做一種獨立的服務抽離出的。

因為currentSession是執行緒級別的,所以,只要業務邏輯方法在同一個執行緒中,就不會擔心上面的問題。這也是currentSession的一個優越處之一。

使用currentSession:

1.在配置檔案中將執行緒配置成Thread級別的。

<propertyname="hibernate.current_session_context_class">thread</property>

2.呼叫sessionFactory的getCurrentSession方法:

publicvoid addUser(User user) {

    Session session = null;

    try {

       session =HibernateUtils.getSessionFactory().getCurrentSession();

       session.beginTransaction();      

       session.save(user);        

       Loglog = new Log();

       log.setType("操作日誌");

       log.setTime(new Date());

       log.setDetail("XXX");      

       LogManager logManager = newLogManagerImpl();

       logManager.addLog(log);       

       session.getTransaction().commit();

    }catch(Exception e) {

       e.printStackTrace();

       session.getTransaction().rollback();   

    }

}

使用openSession:

public void addUser(User user) {

      Sessionsession = null;

      try{

         session= HibernateUtils.getSession();

         session.beginTransaction();

// 若干操作…………        

         session.getTransaction().commit();

      }catch(Exceptione) {

         e.printStackTrace();

         session.getTransaction().rollback();

      }finally{

         HibernateUtils.closeSession(session);

      }

   }

 

使用HibernateDaoSupport宣告式事務:

    Spring與Hibernate的整合使用最多的是HibernateDaoSupport,它對session的獲取以及事務做了進一步的封裝,只需要關注dao的實現,而不用擔心某個地方的事務是否關閉。

this.getHibernateTemplate().save(user);

關於異常與事務回滾:   

    Spring在遇到執行期異常(繼承了RuntimeException)的時候才會回滾,如果是Exception(如使用者輸入密碼錯誤)丟擲就好,事務會繼續往下進行。

    Spring對異常的處理的靈活性還是比較高的,可以配置遇到某個Exception進行回滾,某個RuntimeException不回滾,但是對於EJB就沒有這麼靈活了,EJB相當於是固定的套餐。

不會回滾:  

public void addUser(User user)

   throws Exception {

      this.getHibernateTemplate().save(user);

         //若干操作……          

      throw new Exception();

   }

回滾:

  public void addUser(User user) {

         this.getHibernateTemplate().save(user);    

         //若干操作……       

         throw new RuntimeException();

   }

Spring與Hibernate的整合,使用HibernateDaoSupport的配置:

   在ssh框架應用中,Spring與Hibernate的事務整合基本上是比較固定的,我們把事務的整合單獨配置到applicationContext-common.xml中:

<?xml version="1.0"encoding="UTF-8"?> 

<beansxmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:tx="http://www.springframework.org/schema/tx"

        xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd

          http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd

           http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

   <!--配置SessionFactory -->

   <beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

      <propertyname="configLocation">

         <value>classpath:hibernate.cfg.xml</value>

      </property>

   </bean>
  

   <!--配置事務管理器 -->

   <beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager">

      <propertyname="sessionFactory">

         <refbean="sessionFactory"/>        

      </property>

   </bean>
  

   <!--那些類那些方法使用事務 -->

   <aop:config>

      <aop:pointcutid="allManagerMethod" expression="execution(*com.bjpowernode.usermgr.manager.*.*(..))"/>

      <aop:advisorpointcut-ref="allManagerMethod" advice-ref="txAdvice"/>

   </aop:config>
  

   <!--事務的傳播特性 --> 

   <tx:adviceid="txAdvice" transaction-manager="transactionManager">

      <tx:attributes>

         <tx:methodname="add*" propagation="REQUIRED"/>

         <tx:methodname="del*" propagation="REQUIRED"/>

         <tx:methodname="modify*" propagation="REQUIRED"/>

         <tx:methodname="*" propagation="REQUIRED"read-only="true"/>

      </tx:attributes>

   </tx:advice>

</beans>

因為在hibernate.cfg.xml中添加了如下配置,所以,在tomcat等容器啟動的時候,會自動將相應的bean物件建立。

    <propertyname="hibernate.hbm2ddl.auto">update</property>

applicationContext-beans.xml:

    通常將業務邏輯對實現類的引用單獨的xml檔案中,同時,在實現類中不能忽略sessionFactory工廠的注入。

<?xml version="1.0"encoding="UTF-8"?> 

<beansxmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:aop="http://www.springframework.org/schema/aop"

       xmlns:tx="http://www.springframework.org/schema/tx"

       xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd

           http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd

          http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

          

   <beanid="userManager" class="com.bjpowernode.usermgr.manager.UserManagerImpl">

      <propertyname="sessionFactory" ref="sessionFactory"/>

      <propertyname="logManager" ref="logManager"/>

   </bean>
  

   <beanid="logManager"class="com.bjpowernode.usermgr.manager.LogManagerImpl">

      <propertyname="sessionFactory" ref="sessionFactory"/>

   </bean>

</beans>

事務傳播特性:

   為了保證呼叫的業務邏輯方法都使用同一個事務,通常都使用REQUIRED這個級別,它表示:如果上一個方法中有事務,就直接使用,如果沒有,就建立一個事務,這樣,一旦事務建立了後,後續呼叫的方法就不會再建立。

   其他的事務傳播特性見下表:


Spring事務的隔離級別:

   1. ISOLATION_DEFAULT: 這是一個PlatfromTransactionManager預設的隔離級別,使用資料庫預設的事務隔離級別。

        另外四個與JDBC的隔離級別相對應。

   2. ISOLATION_READ_UNCOMMITTED: 這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的資料。

        這種隔離級別會產生髒讀,不可重複讀和幻像讀。

   3. ISOLATION_READ_COMMITTED: 保證一個事務修改的資料提交後才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的資料

   4. ISOLATION_REPEATABLE_READ: 這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。

        它除了保證一個事務不能讀取另一個事務未提交的資料外,還保證了避免下面的情況產生(不可重複讀)。

   5. ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。

     除了防止髒讀,不可重複讀外,還避免了幻像讀。

    事務隔離級別主要應用在對大資料的處理方面,與鎖的機制是密不可分的,這裡不贅述。