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

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

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

    資料整理

     

    ThreadLocal模式下管理的Session會在事務(wù)提交后自動關(guān)閉!

    ??
    縮略顯示????

    ThreadLocal模式下管理的Session會在事務(wù)提交后自動關(guān)閉!

    關(guān)鍵字: ? Hibernate????

    最近對Hibernate的ThreadLocal Session模式有點興趣。于是根據(jù)曹曉鋼翻譯的Hibernate Reference做了個小測驗,結(jié)果發(fā)現(xiàn)了一個小bug。
    代碼很簡單,都是利用Hibernate Reference中現(xiàn)成的代碼。
    首先是一個輔助的得到線程安全的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;
    }
    }
    然后是一個測試插入數(shù)據(jù)的代碼。也很簡單,也是仿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();
    }
    }

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

    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"

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

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

    于是把DEBUG信息調(diào)用出來,發(fā)現(xiàn)了以下幾句提示:
    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關(guān)閉了,而且是在 事務(wù)結(jié)束以后自動關(guān)閉的。
    DEBUG [main] - after transaction completion
    DEBUG [main] - automatically closing session
    DEBUG [main] - closing session

    那么這個機(jī)制是怎么發(fā)生的呢?

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

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

    他調(diào)用的是一個currentSessionContext的currentSession方法。查找currentSessionContext變量,

    currentSessionContext = buildCurrentSessionContext();

    ,知道了buildCurrentSessionContext方法產(chǎn)生了這個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 的實現(xiàn)類是 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()
    );
    }
    注意第三個參數(shù):isAutoCloseEnabled
    打開Session這個接口,看到 openSession方法中這個參數(shù)是如下描述的:
    * @param autoCloseSessionEnabled Should the session be auto-closed after
    * transaction completion?

    ,就是說session是否應(yīng)該在事務(wù)提交后自動關(guān)閉。

    然后打開 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應(yīng)該在事務(wù)完成后關(guān)閉。

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

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

    評論

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

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

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿(1)

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    主站蜘蛛池模板: 日产国产精品亚洲系列| 亚洲中文字幕伊人久久无码| 亚洲精品蜜桃久久久久久| 免费夜色污私人影院网站| 97无码免费人妻超级碰碰碰碰| 亚洲国产av高清无码| 2021在线永久免费视频| 亚洲人成网站在线观看播放动漫| 日韩精品内射视频免费观看| 亚洲国产成人在线视频| 免费a级毛片高清视频不卡| 亚洲AV成人一区二区三区观看| 日韩免费视频观看| 视频一区二区三区免费观看| www亚洲精品少妇裸乳一区二区| 一级特级aaaa毛片免费观看 | 亚洲熟妇av一区二区三区下载 | 日韩不卡免费视频| 77777午夜亚洲| 国产v片免费播放| 久久国产免费直播| 亚洲综合久久成人69| 成人毛片18女人毛片免费96| 猫咪免费人成网站在线观看入口| 国产亚洲精品无码拍拍拍色欲 | 亚洲欧美aⅴ在线资源| 国产免费怕怕免费视频观看| 国产精品九九久久免费视频| 亚洲高清无在码在线无弹窗| 麻豆国产人免费人成免费视频 | 久久精品人成免费| 亚洲人成欧美中文字幕| 亚洲男人天堂2020| 2015日韩永久免费视频播放| 国产AV无码专区亚洲AV蜜芽 | 四虎影库久免费视频| 中文字幕视频在线免费观看| 亚洲伊人久久大香线蕉影院| 亚洲色图综合在线| 免费电影在线观看网站| 成人无码区免费A∨直播|