<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)

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    主站蜘蛛池模板: 亚洲精品一二三区| 综合自拍亚洲综合图不卡区| 中文字幕乱码亚洲无线三区 | 亚洲伊人久久精品影院| 特级一级毛片免费看| 免费国产综合视频在线看| 国产成人精品亚洲| 国产午夜亚洲精品理论片不卡 | 波多野结衣免费一区视频| 亚洲成AV人片在线观看无| 国产成人AV免费观看| 亚洲一区中文字幕久久| 亚洲日本在线免费观看| 亚洲人成网网址在线看| 成年美女黄网站18禁免费| 亚洲第一se情网站| 亚洲国产精品尤物YW在线观看| av午夜福利一片免费看久久| 国产国拍亚洲精品mv在线观看| 91福利视频免费| 久久综合亚洲色hezyo| 亚洲人成无码久久电影网站| 国产一区二区三区无码免费| av网站免费线看| 亚洲精品国产成人99久久| 无码永久免费AV网站| 国产天堂亚洲国产碰碰| 久久亚洲精品成人综合| 成人免费视频网站www| 亚洲精品亚洲人成在线| 亚洲综合色婷婷七月丁香| 99精品国产成人a∨免费看| 亚洲а∨天堂久久精品9966| 久久99亚洲综合精品首页| 最近中文字幕无免费| 特级毛片A级毛片100免费播放| 亚洲AV日韩AV永久无码下载| 免费无码黄网站在线观看| 色www永久免费网站| 亚洲日本VA中文字幕久久道具| 国外亚洲成AV人片在线观看 |