1. 程式人生 > >多執行緒與hibernate session

多執行緒與hibernate session

1、關於SessionFactory和Session

SessionFactory的實現是執行緒安全的,多個併發的執行緒可以同時訪問一 個SessionFactory並從中獲取Session例項,而Session不是執行緒安全的。Session中包含了數 據庫操作相關的狀態資訊,那麼說如果多個執行緒同時使用一個Session例項進行CRUD,就很有可能導致資料存取的混亂。每個執行緒/事務應該從一個SessionFactory獲取自己的session例項,才能在新執行緒中使用事務和延遲載入等功能,否則會曝出no session異常。

 解決辦法:
  1. new Runnable() {  
  2.                 @Override
  3.                 publicvoid run() {  
  4. //                  ----------繫結session到當前執行緒------------
  5.                     SessionFactory sessionFactory = (SessionFactory)applicationContext.getBean("sessionFactory");  
  6.                     boolean participate = ConcurrentUtil.bindHibernateSessionToThread(sessionFactory);  
  7. //                  ---------你的業務---------------
  8. <pre name="code"class="java">//                  ----------關閉session------------                   
  9.                     ConcurrentUtil.closeHibernateSessionFromThread(participate, sessionFactory);  
  10.                 }  
  11.             }  

其中applicationContext.getBean("xxx"),可能涉及到多執行緒的spring註解注入問題


bindHibernateSessionToThread方法:
  1. publicstaticboolean bindHibernateSessionToThread(SessionFactory sessionFactory) {  
  2.     if (TransactionSynchronizationManager.hasResource(sessionFactory)) {  
  3.         // Do not modify the Session: just set the participate flag.
  4.         returntrue;  
  5.     } else {  
  6.         Session session = sessionFactory.openSession();  
  7.         session.setFlushMode(FlushMode.MANUAL);  
  8.         SessionHolder sessionHolder = new SessionHolder(session);  
  9.         TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);  
  10.     }  
  11.     returnfalse;  
  12. }  
closeHibernateSessionFromThread方法
  1. publicstaticvoid closeHibernateSessionFromThread(boolean participate, Object sessionFactory) {  
  2.     if (!participate) {  
  3.         SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.unbindResource(sessionFactory);  
  4.         SessionFactoryUtils.closeSession(sessionHolder.getSession());  
  5.     }  
  6. }  

事務邊界則由aop或者Transactional標記來控制,示例程式碼只是保證具備事務性的方法在需要的時候能從當前執行緒中獲得session物件。

上述程式碼大部分擷取自Spring的OpenSessionInViewFilter。

2、session的建立:

  Hibernate中的Session通過SessionFactory來建立,具體的建立方式有兩種:

  SessionFactory.getCurrentSession()、SessionFactory.openSession() ;

  這兩種建立Session的方式主要有如下差別:

  a:getCurrentSession建立的session會繫結到當前執行緒,而openSession不會。

  b:getCurrentSession建立的執行緒會再事務回滾或事務提交後自動關閉,而openSession必須手動關閉

  c:getCurrentsession需要在hibernate.cfg.xml檔案中新增配置:                                      <propertyname="current_session_context_class">thread</property>

3、spring hibernate session

使用hibernate進行資料庫操作時,需要session,並且需要對sesssion進行事務管理.

當使用spring來整合hibernate時,spring會幫我們管理session的事務,因此無需我們手動操作事務(提交、回滾等)。

在Spring託管中,session並不是程式設計師自己控制的,session的生命週期交由Spring管理。影響session生命週期的情況有這幾種:

  1. 使用SessionFactory.getCurrentSession()方法。

  2. 使用HibernateTemplate來遮蔽對session的直接訪問。

  3. 使用HibernateTransactionManager,並在session使用區域外圍包裝了本地事務,甚至是事務巢狀。

  4. 使用了JtaTransactionManager,並在session使用區域外圍包裝了Jta事務,甚至是事務巢狀。

  5. 使用了OpenSessionInViewFilter。