1.在 Hibernate3 的 hibernate.cfg.xml 配置文件中有這麼一條: <property name="current_session_context_class">thread</property> 官方對他的解釋以下: 首先,只要你持有SessionFactory,大可在任什麼時候候、任何地點調用這個方法:getCurrentSession() 方法總會返回「當前的」工做單元。記得咱們在hibernate.cfg.xml中把這一配置選項調整爲"thread"了嗎? 所以,當前工做單元的範圍就是當前執行咱們應用程序的Java線程。可是,這並不是老是正確的。 Session在第一次被使用的時候,或者第一次調用getCurrentSession()的時候,其生命週期就開始。 而後它被Hibernate綁定到當前線程。當事務結束的時候,無論是提交仍是回滾,Hibernate也會把 Session從當前線程剝離,而且關閉它。倘若你再次調用getCurrentSession(),你會獲得一個新的Session,而且開始一個新的工做單元。 可能上面的解釋有些看不懂。 先解釋一下線程綁定,爲何要把session與線程綁定呢? 例如咱們要寫一個Servlet實現session的重用 public class TestServlet extends HttpServlet { private org.hibernate.Session thisThreadsSession; public void doGet(...) throws ... { thisThreadsSession = 當前線程中已打開的Session(); doSomething();{//基於當前session的存取操做} thisThreadsSession.flush(); } } 注意在通常狀況下,應用服務器中每一個Servlet只有一個實例,因此在上面的狀況下,多線程併發調用該 TestServlet的惟一實例,其中的 thisThreadsSession 會被各個線程不停的重置,發生的問題就是A線程 可能訪問到C線程的Session。 解決方法就是使用ThreadLocal線程:他爲每一個線程維護一個私有變量空間,也就是爲每一個線程在JVM中維護一個私有Map,Map的Key是當前線程ID,而Value則是經過ThreadLocal.set方法保存的對象實例(這裏就是該線程打開的Hibernate的Session實例) 實現代碼以下: public class TestServlet extends HttpServlet { private ThreadLocal localObjectInThisThread = new ThreadLocal(); public void doGet(...) throws ... { localObjectInThisThread.set(org.hibernate.Session 當前線程中已打開的Session); doSomething(); } public void doSomething() { org.hibernate.Session thisThreadsSession = (org.hibernate.Session) localObjectInThisThread.get(); //基於當前session的存取操做 ...... thisThreadsSession.flush(); } } 從代碼看出,localObjectInThisThread.get()獲得的Session老是當前線程的Session,這就是所謂的線程綁定。 2. Hibernate 官方提供的示例代碼 SessionFactoryUtil或者Eclipse的Hibernate插件自動產生的工具類 HibernateSessionFactory(注意不是hibernate.jar中的org.hibernate.SessionFactory)中有一個靜態函數 getSession public static Session getSession() throws HibernateException { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession (): null; threadLocal.set(session); } return session; } 經過前面的分析,很容易看出她返回的是與線程綁定的Session 那麼這個getSession()方法和前面提起的SessionFactory.getCurrentSession()有什麼異同呢? 相同的地方是:第一次調用getSession()或SessionFactory.getCurrentSession()時,打開新Session,並把它與當前線程綁定。 不一樣的地方是:當事務被Commit時,SessionFactory.getCurrentSession()返回的Session會自動關閉,而 getSession()返回的Session仍然打開,須要顯式關閉才行(也許是爲了便於線程內重用吧)。 最後再讀一遍開始的官方解釋,相信會有更深的體會: 首先,只要你持有SessionFactory,大可在任什麼時候候、任何地點調用這個方法:getCurrentSession() 方法總會返回「當前的」工做單元。記得咱們在hibernate.cfg.xml中把這一配置選項調整爲"thread"了嗎?所以,當前工做單元的範圍就是當前執行咱們應用程序的Java線程。可是,這並不是老是正確的。 Session在第一次被使用的時候,或者第一次調用getCurrentSession()的時候,其生命週期就開始。而後它被Hibernate綁定到當前線程。當事務結束的時候,無論是提交仍是回滾,Hibernate也會把Session從當前線程剝離,而且關閉它。倘若你再次調用getCurrentSession(),你會獲得一個新的Session,而且開始一個新的工做單元。
|