Hibernate——ThreadLocal模式下管理的Session會在事務提交後自動關閉
最近對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();是不對的,這句程式碼是完全多餘的。
相關推薦
Hibernate——ThreadLocal模式下管理的Session會在事務提交後自動關閉
最近對Hibernate的ThreadLocal Session模式有點興趣。於是根據曹曉鋼翻譯的Hibernate Reference做了個小測驗,結果發現了一個小bug。 程式碼很簡單,都是利用Hibernate Reference中現成的程式碼。
ThreadLocal模式下管理的Session會在事務提交後自動關閉!
最近對Hibernate的ThreadLocal Session模式有點興趣。於是根據曹曉鋼翻譯的Hibernate Reference做了個小測驗,結果發現了一個小bug。 程式碼很簡單,都是利用Hibernate Reference中現成的程式碼。 首先是一個
ThreadLocal模式下管理的Session會在事務提交後自動關閉
public class HibernateUtil { public static final SessionFactory sessionFactory; static{ try { sessionFactory = new Configuration().configure().buildSessio
ThreadLocal模式下管理的Session會在事務提交後自動關閉!(摘自http://zgdhj95.javaeye.com/blog/36353)
最近對Hibernate的ThreadLocal Session模式有點興趣。於是根據曹曉鋼翻譯的Hibernate Reference做了個小測驗,結果發現了一個小bug。 程式碼很簡單,都是利用Hibernate Reference中現成的程式碼。 首先是一個輔助的得到執行緒安全
SQL Server事務日誌管理的進階,第5級:在完全恢復模式下管理日誌
SQL Server事務日誌管理的進階,第5級:在完全恢復模式下管理日誌 原文連結:http://www.sqlservercentral.com/articles/Stairway+Series/73785/ 託尼·戴維斯(Tony Davis)著,2012年1月27日
翻譯《Stairway to SQL Server Replication: Level 5- Managing the Log in Full Recovery Mode》 SQL Server事務日誌管理的進階,第5級:在完全恢復模式下管理日誌
SQL Server事務日誌管理的進階,第5級:在完全恢復模式下管理日誌 SQL Server事務日誌管理的進階,第5級:在完全恢復模式下管理日誌 作者:託尼·戴維斯(Tony Davis) 時間:2012年1月27日 原文連結:http://www.sqlser
第五次翻譯:SQL Server事務日誌管理的進階,第5級:在完全恢復模式下管理日誌
SQL Server中事務日誌管理的階梯,第5級:在完全恢復模式下管理日誌 作者:Tony Davis,2012/01/27 文章轉載自:http://www.sqlservercentral.com/articles/Stairway+Series/73785/ 該系列
form表單下點選button按鈕提交後頁面重新整理問題解決
button,input type=button按鈕在IE和w3c,firefox瀏覽器區別 當在IE瀏覽器下面時,button標籤按鈕,input標籤type屬性為button的按鈕是一樣的功能,不會對錶單進行任何操作。 但是在W3C瀏覽器,如Firefox下就需要注意了,button標籤按鈕會提
bootstrap的dropdown-menu(下拉選單)點選選項後不關閉的方法
下面的例子是bootstrap下拉選單的例子 1、html <div class="dropdown"> <button type="button" class="btn dropdown-toggle" id="dro
Laravel框架在ubuntu下的定時任務【過期訂單自動關閉】
轉載了原作者的文章並結合自己的理解有所修改。Ubuntu 下,命令列輸入 crontab -e 打開了一個檔案 然後在最後加入 這技術定時器,* * * * * php /path-to-your-project/artisan schedule:run >&g
windows環境下svn本地提交後自動更新提交到伺服器的專案根目錄
【需求分析】:如果總是用FTP每次都得開啟FTP軟體,而且有時還會超時,並且存在程式碼衝突的問題,所以使用SVN替代FTP是個很不錯的選擇【注意事項】:在使用此功能之前先確保的你的本地客戶端和伺服器端的版本不能相差太大,否則可能會提示客戶端版本太舊等問題【具體細節】:至
linux下監視程序 崩潰掛掉後自動重啟的shell指令碼
如何保證服務一直執行?如何保證即使服務掛掉了也能自動重啟?在寫服務程式時經常會碰到這樣的問題。在Linux系統中,強大的shell就可以很靈活的處理這樣的事務。 下面的shell通過一個while-do迴圈,用ps -ef|grep 檢查loader程序是否正在執行,
解決Hbase啟動後,hmaster會在幾秒鐘後自動關閉(停掉)!!!
兜兜轉轉,嘗試了好多種方法,終於是好了,真的是沒有度娘解決不了的問題!哈哈哈哈 在日誌(身為小白白的我,一開始日誌在哪我都不知道!路徑:/usr/local/hadoop/app/hbase-0.98.8/logs/hbase-hadoop-master-Master.l
ubuntu下設定Iptables在重啟後自動生效
save roles to a file iptables-save /etc/iptables.roles edit /etc/network/interfaces v
JmsTemplate 和activemq中事務提交後執行訊息
正常情況下,mq發出訊息後會立即執行,但是在分散式事務執行過程中,會有這樣的一種情況,即方法執行後,事務成功提交才希望訊息執行,這樣就需要配置一下JmsTemplate,兩種方法 1)在spring 配置檔案中新增jmsTemplate的屬性sessionTransa
sql伺服器第5級事務日誌管理的階梯:完全恢復模式下的日誌管理
sql伺服器第5級事務日誌管理的階梯:完全恢復模式下的日誌管理 原文連結http://www.sqlservercentral.com/articles/Stairway+Series/73785/ 作者 Tony Davis, 2012/01/27 系列 本文是階
利用ThreadLocal模式管理Session
我們知道Session是由SessionFactory負責建立的,而SessionFactory的實現是執行緒安全的,多個併發的執行緒可以同時訪問一個SessionFactory並從中獲取Session例項,那麼Session是否是執行緒安全的呢?很遺憾,答案是否定的。Session中包含了資料庫操作相
ThreadLocal管理下的Session
ThreadLocal並不是名字直接釋義的執行緒本地實現版本,其實它是一個執行緒中的區域性變數。 它的功能非常簡單,就是為使用某一變數的執行緒提供一個該變數的副本,使其可以對該副本進行操作,而不會影響
架構設計 | 基於Seata中介軟體,微服務模式下事務管理
原始碼地址:[GitHub·點這裡](https://github.com/cicadasmile/spring-cloud-base) || [GitEE·點這裡](https://gitee.com/cicadasmile/spring-cloud-base) # 一、Seata簡介 ## 1、Sea
(2.7)備份與還原--在完全恢復模式下事務日誌的角色
ges 需要 很多 對數 for 事情 mage .com .html 簡介 生產環境下的數據是如果可以寫在資產負債表上的話,我想這個資產所占的數額一定不會小。而墨菲定律(事情如果有變壞的可能,無論這種可能性有多小,它總會發生)仿佛是給DBA量身定做的。在上篇文章介