<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 謝瑋 閱讀(1799) 評論(1)  編輯  收藏 所屬分類: 數據持久化

    評論

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

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

    導航

    統計

    常用鏈接

    留言簿(1)

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    主站蜘蛛池模板: 免费在线观看的网站| 久久精品无码精品免费专区| 亚洲午夜福利精品久久| 一区二区三区精品高清视频免费在线播放| 免费**毛片在线播放直播| 美女被cao网站免费看在线看| 色天使亚洲综合一区二区| 亚洲乱码一二三四五六区| 亚洲AV永久无码精品| 亚洲 综合 国产 欧洲 丝袜 | 精品国产污污免费网站aⅴ| 精品97国产免费人成视频 | 午夜毛片不卡免费观看视频| 777成影片免费观看| 亚洲免费人成在线视频观看| 一级毛片在线免费播放| 男女啪啪免费体验区| 久久国产亚洲精品| 亚洲AV成人噜噜无码网站| 亚洲人成网址在线观看| 久久久久亚洲精品天堂久久久久久 | 成人啪精品视频免费网站| 57pao国产成永久免费视频| 久久亚洲免费视频| 三级网站在线免费观看| 中出五十路免费视频| 国产黄片不卡免费| 久久www免费人成看国产片| 一区二区三区免费在线视频| 一个人看的在线免费视频| 国产va免费观看| 久久久久久国产a免费观看不卡| 一级毛片视频免费| yellow视频免费在线观看| a一级爱做片免费| 中国国语毛片免费观看视频| 在线视频网址免费播放| 99在线视频免费观看| 精品在线免费观看| 亚洲av午夜福利精品一区人妖| 亚洲中文字幕丝袜制服一区|