Could not obtain transaction-synchronized Session for current thread
今天運行程序時 報了 如下的錯誤。
Could not obtain transaction-synchronized Session for current thread
在Spring中使用Hibernate,如果我們配置了TransactionManager,那麽我們就不應該調用SessionFactory的openSession()來獲得Sessioin,因為這樣獲得的Session並沒有被事務管理。我們應該使用getCurrentSession()
Spring 修改
在Spring中,如果我們在沒有配置TransactionManager並且沒有事先調用SessionFactory.openSession()的情況直接調用getCurrentSession(),那麽程序將拋出“No Session found for current thread”異常。如果配置了TranactionManager並且通過@Transactional或者聲明的方式配置的事務邊界,那麽Spring會在開始事務之前通過AOP的方式為當前線程創建Session,此時調用getCurrentSession()將得到正確結果。
可以由上面的看到首先在Spring 和Hibernate 整合時 ,如果我們沒有配置TranscationManager,但是直接調用了getCurrentSession(),那麽就出現了這個錯誤,所以我們現在首先要將TranscationManager 加入進來。
解決辦法:
1. 在Spring中加入事務 即使這個只是個查詢的事務,不過我們可以設置此為一個ReadOnly 事務
1) 將事務的標簽加入對應的方法中
1 @Transactional(readOnly = true) 2 public int findBookPriceByIsbn(String isbn) {3 String hql = "SELECT b.price FROM Book b WHERE b.isbn = ?"; 4 Query<Integer> query = getSession().createQuery(hql).setParameter(0, isbn); 5 return query.uniqueResult(); 6 }
2)在xml中配置事務
1 <bean id="transactionManager" 2 class="org.springframework.orm.hibernate5.HibernateTransactionManager"> 3 <property name="sessionFactory" ref="localSessionFactoryBean"></property> 4 </bean> 5 6 <tx:annotation-driven transaction-manager="transactionManager" />
Hibernate中修改:
其實我們也可以在Hibernate 中進行修改 , 當我們不需要Spring的時候
然而,產生以上異常的原因在於Spring提供了自己的CurrentSessionContext實現,如果我們不打算使用Spring,而是自己直接從hibernate.cfg.xml創建SessionFactory,並且為在hibernate.cfg.xml
中設置current_session_context_class為thread,也即使用了ThreadLocalSessionContext,那麽我們在調用getCurrentSession()時,如果當前線程沒有Session存在,則會創建一個綁定到當前線程。
我們可以看到 當我們不使用Spring的時候 其實也會出現這個錯誤,歸根結底在於有沒有開這個session
解決方案:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> 8 <property name="hibernate.show_sql">true</property> 9 <property name="hibernate.format_sql">true</property> 10 <property name="hibernate.hbm2ddl.auto">update</property>
//添加新的屬性 11 <property name="current_session_context_class">thread</property> 12 </session-factory> 13 </hibernate-configuration>
web.xml解決方案:
在項目中,利用SessionFactory.getCurrentSession()方法獲取hibernate的會話,當在一個controller方法中多次使用訪問數據庫,會報出錯誤:Could not obtain transaction-synchronized Session for current thread
在這裏應該用一下spring中的OpenSessionInViewFilter,否則,需要每次使用完成後關閉session,下一次使用才不會報錯,但是又涉及到一個lazy loading的問題,關閉session之後就無法懶加載,所以使用OpenSessionInViewFilter是一個兩全的選擇
1 <filter> 2 <filter-name>SpringOpenSessionInViewFilter</filter-name> 3 <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> 4 </filter> 5 <filter-mapping> 6 <filter-name>SpringOpenSessionInViewFilter</filter-name> 7 <url-pattern>/*</url-pattern> 8 </filter-mapping>
參考資料:
1.SpringMVC4+Hibernate4運行報錯Could not obtain transaction-synchronized Session for current thread
2. Hibernate4 No Session found for current thread原因
3. spring+hibernate Could not obtain transaction-synchronized Session for current thread
Could not obtain transaction-synchronized Session for current thread