1. 程式人生 > >hibernate中的ThreadLocalSessionContext和Transaction的關係

hibernate中的ThreadLocalSessionContext和Transaction的關係

       最近在做一個鐵科院的醫保專案框架是SSH,這種經典框架相信很多人對這個都很熟悉,不過對有些概念性的東西不知道你是否清楚,例如我們都知道hibernate通過session來操作資料庫完成CRUD操作,Spring在同hibernate整合的時候可以將hibernate的sessionfactory拿過來管理,為了更方便操作資料庫spring封裝了一個getHibernateTemplate類,該類也可以完成CRUD操作,在使用靈活行方面比hibernate靈活了一些,操作也簡便。

       對資料庫的操作都需要控制事務保證操作原子性,session在操作資料庫的時候事務是怎麼控制的呢,我們只知道事務是隨著session一起開啟和關閉的,具體來看一下是如何實現。

       通過寫底層的一些方法,瞭解了getCurrentSession()與openSession()的區別,前者是從當前執行緒中獲取session,使用完後不需要自己關閉;後者是開啟一個新的session,需要自己手動開發和關閉;

       我們操作的是session,它和事務有什麼關係呢?換句話說,session和事務生命週期是否相同?分別何時開啟?何時關閉?

       想要清楚這兩者的關係,先要了解session機制,session是hibernate框架中一個操作ORM對映關係的介面,該介面有三種類型,分別為ThreadLocalSessionContext、JTASessionContext、ManagedSessionContext,這三個實現類實現了CurrentSessionContext介面。

       getCurrentSession()這個方法得到的就是CurrentSessionContext介面,提供的預設實現類為ThreadLocalSessionContext

<span style="font-size:14px;">SessionFactory類
public abstract interface SessionFactory extends Referenceable, Serializable
{
  public abstract Session openSession(Connection paramConnection);

  public abstract Session getCurrentSession()
throws HibernateException;
}
SessionFactory實現類
public final class SessionFactoryImpl
  implements SessionFactory, SessionFactoryImplementor
{

 private final transient CurrentSessionContext currentSessionContext;

 public Session getCurrentSession()
    throws HibernateException
  {
    if (this.currentSessionContext == null) {
      throw new HibernateException("No CurrentSessionContext configured!");
    }
    return this.currentSessionContext.currentSession();
  }
}
CurrentSessionContext接口裡面只有一個方法,currentSession()
public abstract interface CurrentSessionContext extends Serializable
{
  public abstract Session currentSession()
    throws HibernateException;
}
public class ThreadLocalSessionContext
  implements CurrentSessionContext
{  
   private static final ThreadLocal context = new ThreadLocal();
   
   public final org.hibernate.classic.Session currentSession()
    throws HibernateException
  {
    org.hibernate.classic.Session current = existingSession(this.factory);
    if (current == null) {
      current = buildOrObtainSession();

      current.getTransaction().registerSynchronization(buildCleanupSynch());

      if (needsWrapping(current)) {
        current = wrap(current);
      }

      doBind(current, this.factory);
    }
    return current;
  }


}
</span>

       Session與Transaction進行關聯是在底層session實現時操作的,你是否記得代理模式的作用,代理物件可以在客戶端和目標物件之間起到中介的作用,可以增加一些額外,這樣起到了保護目標物件的作用,在這裡事務正式通過代理模式給session新增事務的

如果只從ThreadLocalSessionContext的名稱上看,它所做的就是把一個session繫結到當前執行緒上,讓當前執行緒作為session的上下文。這樣,在service裡不同的dao通過sessionFactory.getCurrentSession()得到的將是當前執行緒上的同一個session,這是非常必要的做法,通過使用同一個session確保了持久化物件的一致性。但是從ThreadLocalSessionContext的程式碼來看,它並只是做了這一件事,它還做了另外一件非常“醒目”的事情:即給session包裹了一層代理org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper,這個代理將攔截session的操作,對session的使用做出瞭如下的限制:

1.在沒有顯式地開始一個事務之前,不能使用session的任何資料訪問方法。

2.一旦事務提交,session將自動close。

       通過上面這樣的限制就使得事務同session的週期變的一致了,由於session放在了一個ThreadLocal裡面,如此以來,threadlocal、session、transaction三者的生命週期是一致的,達到了對於同一個請求在同一個執行緒同一個事務中,session也是同一個session,既保證了持久化物件的一致性,又保證了事務的機制。

        相反在提交事務之後,如果再從threadlocal中取得session將是一個新的session物件。因此,session的週期和事務是繫結在一起的。

       ThreadLocal在這裡當做上下文來存放session物件,每次在用的時候只需要從這裡面取出來就可以了。