JTA事務總

剛看完《hibernate in action》,前段時間hiberante3又發佈了3.0.2版,對於hibernate的這種更新路線我還是比較喜歡的,2.x的版本繼續更新發展這對於已經在項目中應用hibernate的人來說是再慶幸不過的了(不過這也許是廢話,如果GAVIN KING不繼續發展2.x誰還敢用3.x,因爲...4.x...),3版本是不兼容2的,整體包名都進行了徹底的變動,如果想移植的話其實工作量也不大很多接口都是一樣的,配置文件也儘量保持以前的規範,而且3會有更多令人興奮的新特性,這種走不同版本分支、不拖泥帶水的革新,至少讓我感覺比一味堅持要兼容老版本的EJB3來得爽!

 

言歸正傳,讓我們回到今天的主題JTA,當然開頭白並非廢話,因爲今天講的是hibernate中的JTA事務應用。


hibernate2中只有JDBCTransaction和JTATransaction兩種事務類,對於使用JTA事務的應用,
應該說JTATransaction適用於絕大部分情況,但是CMT情況將存在一些例外:

通過以上JTATransaction源碼可知,如果調用session.beginTransaction()時已經處於事務狀態,hibernate只是簡單的加入這個事務,這對於Requires和RequiresNew等情況是沒有問題的,但是如果調用session.beginTransaction()時不處於事務環境,那麼JTATransaction將啓動事務。這對於一個通過容器管理(CMT)事務的且不需要啓事務的EJB調用將會存在矛盾。當然對於CMT的情況你可以不調用任何hibernate的Transaction事務函數,只通過session進行CRUD(create、read、update、delete)操作,避開這個例外的情況,但是這存在一個新問題:一般的hibernate操作代碼並不直接手工調用session.flush,而是通過tx.commit時由hibernate內部自動進行flush,所以如果想用以上的小伎倆,那麼請記得在操作最後手工添加session.flush函數。這樣CMT中的代碼片段可以改造如下:


爲了解決以上問題hibernate3進行了改進,增加了CMTTransaction類,以及兩個新屬性:
1:【hibernate.transaction.flush_before_completion】
If enabled, the session will be automatically flushed during the before completion
phase of the transaction. (Very useful when using Hibernate with CMT.)

2:【hibernate.transaction.auto_close_session】
If enabled, the session will be automatically closed during the before completion
phase of the transaction.(Very useful when using Hibernate with CMT.)

所以對於CMT的情況,只要將以上兩個參數設置爲true,hibernate自動會在事務提交時進行flush和close,具體實現細節可以看看org.hibernate.transaction.CacheSynchronization的實現和
JDBCContext中的registerSynchronizationIfPossible函數。由於CMT情況下容器對於RuntimeException的異常將進行事務回滾,所以可以通過在需要回滾事務時拋出RuntimeException類型的異常,那麼甚至可以完全不用操作hibernate的Transaction類的任何API。

對於JTA的配置問題注意以下幾點:

tx = (UserTransaction) ctx.lookup("javax.transaction.UserTransaction");
tx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");

對於weblogic由於以上兩種方式都能找到JTA事務對象,而hibernate默認的查找名如下爲【java:comp/UserTransaction】,所以在weblogic中設置啓用JTA方式,只需要配置【hibernate.transaction.factory_class】屬性爲【org.hibernate.transaction.JTATransactionFactory】,【hibernate.transaction.manager_lookup_class】屬性不配也行。

還有一種方式通過配置如下屬性,可以指定UserTransaction的JNDI名
<property name="jta.UserTransaction">javax.transaction.UserTransaction</property>

另外還有一個JTA調用超時問題,對於weblogic默認是30秒,可以通過控制檯進行動態配置,如果事務處理操作配置的超時時間對於weblogic的情況,容器將會自動調用internalRollback()。

最後一點需要注意的是數據庫事務隔離級別的設置:

----------------------------------------------------------------

■ Read uncommitted:
這個級別是不安全的,事務中的查詢會讀到當前其它事務正在設置當時還未提交的數據

■ Read committed:
這個級別相對比較安全,事務中讀到的數據都是已經得到提交的數據,但是如果兩次讀取同一個條記錄,但是在兩次讀取的過程中有另外的事務更改了改記錄併成功提交的話,則會出現同一事務中兩次讀取同一條記錄數據不一致的情況。這種情況很少出現,因爲一般同一事務的程序不會重複讀取同一條記錄,如果用hibernate就更安全了,hibernate的一級緩存不會讓程序向數據庫兩次讀取同一條記錄。

■ Repeatable read:
這個級別解決了同一事務兩次讀取數據結果不同的情況,這個級別也是很多數據庫的默認事務級別(如mysql)

■ Serializable:
這個級別會使所有事務串行化工作,每個事務只能排隊進行數據庫操作,類似單線程的Servlet的工作機制,這樣在並非量較高的數據庫訪問時,數據庫操作效率將極其底下,應該避免使用
----------------------------------------------------------------
hibernate中通過【hibernate.connection.isolation】屬性進行設置,但是如果hibernate的數據庫連接是通過數據源獲得的話,hibernate則不再對事務隔離級別進行設置,所以對於數據源的到的數據庫連接只能通過設置應用服務器配置數據庫隔離級別,當然也可以通過Connection con = session.connection();con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);進行手工設置。


實際使用中發現,如果用weblogic的JTA的話,需要用weblogic的datasource的Connection,否則update操作不會成功。
Context ctx = new InitialContext();
Session session = sessionFactory.openSession(((DataSource)ctx.lookup("mydatasource")).getConnection);


本文引用地址:http://www.cnpoint.com/framwwork/2006/1230/content_4816.htm

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