Hibernate4中使用getCurrentSession報Could not obtain transaction-synchronized Session for current thread

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
at com.web.soulyogaadmin.member.dao.impl.MemberDaoImpl.showOneMember(MemberDaoImpl.java:77)
at com.web.soulyogaadmin.member.service.impl.MemberServiceImpl.showOneMember(MemberServiceImpl.java:47)
at com.web.webservice.member.action.MemberController.findMemberInfoById(MemberController.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

提示無法獲取當前線程的事務同步session,略微奇怪,這和事務有什麼關係..然後百度一下有人說改成用openSession方法就好了,那我又百度了一下這2個方法的區別:

(1)openSession每次打開都是新的Session,所以多次獲取的Session實例是不同的,並且需要人爲的調用close方法進行Session關閉。
(2)getCurrentSession是從當前上下文中獲取Session並且會綁定到當前線程,第一次調用時會創建一個Session實例,如果該Session未關閉,後續多次獲取的是同一個Session實例;事務提交或者回滾時會自動關閉Sesison,無需人工關閉。

看起來這個getCurrentSession方法的確和事務有點關係.然後我加上事務:

複製代碼
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
複製代碼

然後在dao層加上@Transaction註解,再運行ok了..不過好奇驅使吧,看了一下getCurrentSession的源碼(我的demo中用的spring的實現類),關鍵點:

複製代碼
if (TransactionSynchronizationManager.isSynchronizationActive()) {
            Session session = this.sessionFactory.openSession();
            if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
                session.setFlushMode(FlushMode.MANUAL);
            }
            SessionHolder sessionHolder = new SessionHolder(session);
            TransactionSynchronizationManager.registerSynchronization(
                    new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
            TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
            sessionHolder.setSynchronizedWithTransaction(true);
            return session;
 }
 else {
            throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
 }
複製代碼

然後點進去看了一下isSynchronizationActive()方法:

public static boolean isSynchronizationActive() {
        return (synchronizations.get() != null);
    }

get方法說明:

Returns the value in the current thread's copy of this thread-local variable. If the variable has no value for the current thread, it is first initialized to the value returned by an invocation of the initialValue method.

然後再看initialValue的說明:

This implementation simply returns null; if the programmer desires thread-local variables to have an initial value other than null, ThreadLocal must be subclassed, and this method overridden. Typically, an anonymous inner class will be used.

到此問題明瞭了,補充一點之前配置文件中配了事務,不過是原來那種在配置中根據方法名字來定義事務傳播的方式,但是在dao中並沒有繼承它,故實際上是沒有事務的,只有實現.而在spring的事務實現中需要判斷當前線程中的事務是否同步,而沒有事務的時候,那個判斷是否同步的方法會因爲get返回初始的null值而返回false,最終導致throw一個Could not obtain transaction-synchronized Session for current thread的異常.

綜上:spring4+hibernate4,使用hibernate的api的時候需要配置事務的,如果不配置事務會導致獲取當前session拋出異常.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章