1. 程式人生 > >Hibernate4中使用getCurrentSession報Could not obtain transaction-synchronized Session for current thread

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




Dao層直接注入的sessionFactory,然後用getCurrentSession方法獲取session,然後問題來了,直接報錯:
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丟擲異常.

分類:  hibernate, java, spring 標籤:  hibernate4spring4事務getCurrentSessionopenSession