<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    資料整理

     

    ThreadLocal模式下管理的Session會在事務提交后自動關閉!

    ??
    縮略顯示????

    ThreadLocal模式下管理的Session會在事務提交后自動關閉!

    關鍵字: ? Hibernate????

    最近對Hibernate的ThreadLocal Session模式有點興趣。于是根據曹曉鋼翻譯的Hibernate Reference做了個小測驗,結果發現了一個小bug。
    代碼很簡單,都是利用Hibernate Reference中現成的代碼。
    首先是一個輔助的得到線程安全的session的HibernateUtil類,

    public class HibernateUtil {
    public static final SessionFactory sessionFactory;
    static{
    try {
    sessionFactory = new Configuration().configure().buildSessionFactory();
    }
    catch(Throwable ex){
    throw new ExceptionInInitializerError(ex);
    }
    }

    public static final ThreadLocal session = new ThreadLocal();
    public static Session currentSession()
    {
    Session s = (Session) session.get();
    if (s==null )
    {
    s = sessionFactory.getCurrentSession();
    session.set(s);
    }
    return s;
    }
    public static void closeSession()
    {
    Session s = (Session) session.get();
    if (s!=null)
    s.close();
    session.set(null);
    }
    public static SessionFactory getSessionFactory()
    {
    return sessionFactory;
    }
    }
    然后是一個測試插入數據的代碼。也很簡單,也是仿Hibernate Reference上面的代碼。
    public class InsertUser {
    public static void main(String[] args) {
    Session session = HibernateUtil.currentSession();
    Transaction tx= session.beginTransaction();
    TUser user = new TUser();
    user.setName("Emma");
    session.save(user);
    tx.commit();
    HibernateUtil.closeSession();
    }
    }

    就這么簡單一個程序,運行到最后,出現一個錯誤。

    org.hibernate.SessionException: Session was already closed
    at org.hibernate.impl.SessionImpl.close(SessionImpl.java:270)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
    at $Proxy0.close(Unknown Source)
    at Util.HibernateUtil.closeSession(HibernateUtil.java:36)
    at test.InsertUser.main(InsertUser.java:20)
    Exception in thread "main"

    錯誤出現在 HibernateUtil.closeSession(); 這一行,意思是session已經關閉了,再次關閉它就引起異常了。

    不過前面的代碼中只有個tx.commit(); 提交事務 而已,并沒有自動關閉session啊?

    于是把DEBUG信息調用出來,發現了以下幾句提示:
    DEBUG [main] - after transaction completion
    DEBUG [main] - automatically closing session
    DEBUG [main] - closing session
    DEBUG [main] - connection already null in cleanup : no action
    DEBUG [main] - allowing proxied method [close] to proceed to real session
    DEBUG [main] - closing session
    org.hibernate.SessionException: Session was already closed


    特別是下面這3句話引起了我的注意,果然是session關閉了,而且是在 事務結束以后自動關閉的。
    DEBUG [main] - after transaction completion
    DEBUG [main] - automatically closing session
    DEBUG [main] - closing session

    那么這個機制是怎么發生的呢?

    打開了Hibernate3的源碼,我找到了答案。
    首先,根據sessionFactory = new Configuration().configure().buildSessionFactory();
    打開Configuration類的buildSessionFactory()方法,找到sessionFactory的生成語句
    return new SessionFactoryImpl(
    this,
    mapping,
    settings,
    getInitializedEventListeners()
    );
    ,然后找到SessionFactoryImpl的getCurrentSession方法,發現是這么定義的。

    public org.hibernate.classic.Session getCurrentSession() throws HibernateException {
    if ( currentSessionContext == null ) {
    throw new HibernateException( "No CurrentSessionContext configured!" );
    }
    return currentSessionContext.currentSession();
    }

    他調用的是一個currentSessionContext的currentSession方法。查找currentSessionContext變量,

    currentSessionContext = buildCurrentSessionContext();

    ,知道了buildCurrentSessionContext方法產生了這個currentSessionContext 對象。

    private CurrentSessionContext buildCurrentSessionContext() {
    String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS );
    // for backward-compatability
    if ( impl == null && transactionManager != null ) {
    impl = "jta";
    }

    if ( impl == null ) {
    return null;
    }
    else if ( "jta".equals( impl ) ) {
    return new JTASessionContext( this );
    }
    else if ( "thread".equals( impl ) ) {
    return new ThreadLocalSessionContext( this );
    }
    else {
    try {
    Class implClass = ReflectHelper.classForName( impl );
    return ( CurrentSessionContext ) implClass
    .getConstructor( new Class[] { SessionFactoryImplementor.class } )
    .newInstance( new Object[] { this } );
    }
    catch( Throwable t ) {
    log.error( "Unable to construct current session context [" + impl + "]", t );
    return null;
    }
    }
    }

    這個方法就是用來判斷使用JTA管理這個SessionContext還是用ThreadLocal來管理SessionContext的。
    在我們這里是用 ThreadLocal 來管理的,于是找到了currentSessionContext 的實現類是 ThreadLocalSessionContext。

    找到該類的currentSession方法

    public final Session currentSession() throws HibernateException {
    Session current = existingSession( factory );
    if (current == null) {
    current = buildOrObtainSession();
    // register a cleanup synch
    current.getTransaction().registerSynchronization( buildCleanupSynch() );
    // wrap the session in the transaction-protection proxy
    if ( needsWrapping( current ) ) {
    current = wrap( current );
    }
    // then bind it
    doBind( current, factory );
    }
    return current;
    }

    然后跟蹤到 buildOrObtainSession(),就是這里,打開了session。

    protected Session buildOrObtainSession() {
    return factory.openSession(
    null,
    isAutoFlushEnabled(),
    isAutoCloseEnabled(),
    getConnectionReleaseMode()
    );
    }
    注意第三個參數:isAutoCloseEnabled
    打開Session這個接口,看到 openSession方法中這個參數是如下描述的:
    * @param autoCloseSessionEnabled Should the session be auto-closed after
    * transaction completion?

    ,就是說session是否應該在事務提交后自動關閉。

    然后打開 ThreadLocalSessionContext 的isAutoCloseEnabled()方法。

    /**
    * Mainly for subclass usage. This impl always returns true.
    *
    * @return Whether or not the the session should be closed by transaction completion.
    */
    protected boolean isAutoCloseEnabled() {
    return true;
    }
    看到如下提示:Whether or not the the session should be closed by transaction completion ,即無論如何session應該在事務完成后關閉。

    答案就在這里,就是說在ThreadLocal Session模式下面,只要提交了事務,那么session就自動關閉了,因此我參照Hibernate Refernece上面的代碼寫的在事務關閉以后再調用HibernateUtil.closeSession();是不對的,這句代碼是完全多余的。

    posted on 2006-12-18 09:13 謝瑋 閱讀(1800) 評論(1)  編輯  收藏 所屬分類: 數據持久化

    評論

    # re: ThreadLocal模式下管理的Session會在事務提交后自動關閉! 2008-11-07 15:08 劉鑫

    very good. 但是如果把tx.commit拿掉之后,數據沒有插入,但是數據表的標志位卻自增了,什么原因那?  回復  更多評論   

    導航

    統計

    常用鏈接

    留言簿(1)

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    主站蜘蛛池模板: 黄色大片免费网站| 亚洲变态另类一区二区三区| 一级A毛片免费观看久久精品| 永久免费AV无码网站在线观看| 成人亚洲国产va天堂| 韩国日本好看电影免费看| 亚洲精品久久久久无码AV片软件| 成人免费无码大片A毛片抽搐色欲| 亚洲av永久无码精品三区在线4| 无码国产精品一区二区免费| 亚洲国产日韩精品| 日韩亚洲国产综合久久久| 国产精品美女久久久免费| 国产亚洲综合一区柠檬导航| 人妻在线日韩免费视频| 亚洲精品无码久久久久久久| 免费无码又爽又刺激聊天APP| 亚洲精品无码久久久久A片苍井空| 国产一精品一aⅴ一免费| www一区二区www免费| 777亚洲精品乱码久久久久久| 野花高清在线观看免费完整版中文 | 在线观看免费中文视频| 亚洲国产精品综合久久2007| 成人网站免费观看| 国产精品免费视频观看拍拍| 亚洲第一中文字幕| 噜噜嘿在线视频免费观看| 国产精品免费久久久久影院 | 国产亚洲老熟女视频| 无码国产精品一区二区免费式芒果 | 91在线视频免费看| 美女视频黄a视频全免费网站一区| 亚洲宅男天堂在线观看无病毒| 久9久9精品免费观看| 亚洲乱码国产乱码精华| 国产偷国产偷亚洲清高动态图| 黄色免费网站网址| 午夜在线免费视频| 亚洲成年人电影网站| 亚洲午夜精品久久久久久浪潮|