一、什么是Java事務
事務必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫。事務的原子性表示事務執行過程中的任何失敗都將導致事務所做的任何修改失效。一致性表示當事務執行失敗時,所有被該事務影響的數據都應該恢復到事務執行前的狀態。隔離性表示在事務執行過程中對數據的修改,在事務提交之前對其他事務不可見。持久性表示已提交的數據在事務執行失敗時,數據的狀態都應該正確。
通俗的理解,事務是一組原子操作單元,從數據庫角度說,就是一組SQL指令,要么全部執行成功,若因為某個原因其中一條指令執行有錯誤,則撤銷先前執行過的所有指令。更簡答的說就是:要么全部執行成功,要么撤銷不執行。
既然事務的概念從數據庫而來,那Java事務是什么?之間有什么聯系?
實際上,一個Java應用系統,如果要操作數據庫,則通過JDBC來實現的。增加、修改、刪除都是通過相應方法間接來實現的,事務的控制也相應轉移到Java程序代碼中。因此,數據庫操作的事務習慣上就稱為Java事務。
二、為什么需要事務
事務是為解決數據安全操作提出的,事務控制實際上就是控制數據的安全訪問。具一個簡單例子:比如銀行轉帳業務,賬戶A要將自己賬戶上的1000元轉到B賬戶下面,A賬戶余額首先要減去1000元,然后B賬戶要增加1000元。假如在中間網絡出現了問題,A賬戶減去1000元已經結束,B因為網絡中斷而操作失敗,那么整個業務失敗,必須做出控制,要求A賬戶轉帳業務撤銷。這才能保證業務的正確性,完成這個操走就需要事務,將A賬戶資金減少和B賬戶資金增加方到一個事務里面,要么全部執行成功,要么操作全部撤銷,這樣就保持了數據的安全性。
三、Java事務的類型
Java事務的類型有三種:JDBC事務、JTA(JavaTransaction API)事務、容器事務。
1、JDBC事務
JDBC 事務是用 Connection 對象控制的。JDBCConnection 接口( java.sql.Connection )提供了兩種事務模式:自動提交和手工提交。 java.sql.Connection 提供了以下控制事務的方法:
public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
使用 JDBC 事務界定時,您可以將多個 SQL 語句結合到一個事務中。JDBC 事務的一個缺點是事務的范圍局限於一個數據庫連接。一個 JDBC 事務不能跨越多個數據庫
2、JTA(Java Transaction API)事務
JTA是一種高層的,與實現無關的,與協議無關的API,應用程序和應用服務器可以使用JTA來訪問事務。
JTA(Java Transaction API)允許應用程序執行分布式事務處理:在兩個或多個網絡計算機資源上訪問並且更新數據,這些數據可以分布在多個數據庫上,JDBC驅動程序的JTA支持極大地增強了數據訪問能力。
如果計划用 JTA 界定事務,那么就需要有一個實現javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驅動程序。一個實現了這些接口的驅動程序將可以參與 JTA 事務。一個 XADataSource 對象就是一個 XAConnection 對象的工廠。 XAConnection是參與 JTA 事務的 JDBC 連接。
您將需要用應用服務器的管理工具設置 XADataSource 。從應用服務器和 JDBC 驅動程序的文檔中可以了解到相關的指導。
J2EE 應用程序用 JNDI 查詢數據源。一旦應用程序找到了數據源對象,它就調用 javax.sql.DataSource.getConnection() 以獲得到數據庫的連接。
XA 連接與非 XA 連接不同。一定要記住 XA 連接參與了 JTA 事務。這意味着 XA 連接不支持 JDBC 的自動提交功能。同時,應用程序一定不要對 XA 連接調用 java.sql.Connection.commit() 或者java.sql.Connection.rollback() 。相反,應用程序應該使用UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() 。
JTA(Java Transaction API)允許應用程序執行分布式事務處理--在兩個或多個網絡計算機資源上訪問並且更新數據。JDBC驅動程序的JTA支持極大地增強了數據訪問能力。
本文的目的是要提供一個關於的Java事務處理API(JTA)的高級的概述,以及與分布式事務相關的內容。一個事務處理定義了一個工作邏輯單元,要么徹底成功要么不產生任何結果。 一個分布式事務處理只是一個在兩個或更多網絡資源上訪問和更新數據的事務處理,因此它在那些資源之間必然是等價的。在本文中,我們主要關心的是如何處理關系數據庫系統。
我們要討論的分布式事務處理(DTP)模型中包含的組件是:
應用程序
應用程序服務器
事務管理程序
資源適配器
資源管理程序
在以后的內容中,我們將描述這些組件以及它們與JTA和數據庫訪問的關系。
最好把分布式事務處理中包含的組件看作是獨立的過程,而不是考慮它們在一個特定的電腦中的位置。這些組件中的一些可以保存在單機中,或者也可在好幾台機器之間分布。
最簡單的例子:用於本地數據庫事務處理的應用程序
關系數據庫訪問的最簡單的形式僅僅包括應用程序、資源管理程序和資源適配器。應用程序只不過是發送請求到數據庫並且從數據庫中獲取數據的最終用戶訪問點
我們討論的資源管理程序是一個關系數據庫管理系統(RDBMS),比如Oracle或者SQL Server。所有的實際數據庫管理都是由這個組件處理的。
資源適配器是外部空間之間的通信管道組件,或者是請求翻譯器,在單個的本地事務處理中,這是一個JDBC驅動程序。應用程序發送一個用於JDBC驅動程序數據的請求,然后翻譯這個請求並把它通過網絡發送到數據庫中。 數據庫把數據發送回驅動程序,然后把翻譯的結果發送回應用程序。
到目前為止,我們說明了單個的本地事務處理,並且描述了分布式事務處理模型的五個組件中的四個。第五個組件,事務管理程序只有當事務將要被分配的時候才會開始被考慮。
分布式事務處理和事務管理程序
像我們前面所提到的,一個分布式事務處理是一個在兩個或更多網絡資源上訪問和更新數據的事務處理。
這些資源可以由好幾個位於一個單獨服務器上的不同的關系型數據庫管理系統組成,比如說Oracle、SQL Server和Sybase;它們也可以包含存在於若干不同的服務器上的同一種數據庫的若干個實例。在任何情況下,一個分布式事務處理包括各種的資源管理程序之間的協同作用。這個協同作用是事務管理程序。
事務管理程序負責作出要么提交(commit)要么退回(rollback)任何分布式事務處理的決定。一個提交決定應該導致一個成功的事務處理;而退回操作則是保持數據庫中的數據不變。 JTA指定一個分布式事務處理中的事務管理程序和另一個組件之間的標准Java接口:應用程序,應用程序服務器和資源管理程序。
JTA的三個接口部分:
1、UserTransaction,javax.transaction.UserTransaction接口提供能夠編程地控制事務處理范圍的應用程序。 javax.transaction.UserTransaction方法開啟一個全局事務並且使用調用線程與事務處理關聯。
2、Transaction Manager,javax.transaction.TransactionManager接口允許應用程序服務器來控制代表正在管理的應用程序的事務范圍。
3、XAResource,javax.transaction.xa.XAResource接口是一個基於X/OpenCAE Specification的行業標准XA接口的Java映射。
注意,一個限制性環節是通過JDBC驅動程序的XAResource接口的支持。JDBC驅動程序必須支持兩個正常的JDBC交互作用:應用程序和/或應用程序服務器,而且以及JTA的XAResource部分。
編寫應用程序水平代碼的開發者不會關心分布式事務處理管理的細節。 這是分布式事務處理基本結構的工作:應用程序服務器、事務管理程序和JDBC驅動程序。應用程序代碼中唯一的需要注意的就是當連接處於一個分布式事務范圍內的時候,不應該調用一個會影響事務邊界的方法。特別的是,一個應用程序不應該調用Connection方法commit、rollback和setAutoCommit(true),因為它們將破壞分布式事務的基本結構管理。
分布式事務處理
事務管理程序是分布式事務基本結構的基本組件;然而JDBC驅動程序和應用程序服務器組件應該具備下面的特征:
驅動程序應該實現JDBC 2.0應用程序接口,包括OptionalPackage接口XADataSource和XAConnection以及JTA接口XAResource。
應用程序服務器應該提供一個DataSource類,用來實現與分布式事務基本結的交互以及一個連接池模塊(用於改善性能)。
分布式事務處理的第一步就是應用程序要發送一個事務請求到事務管理程序。雖然最后的commit/rollback決定把事務作為一個簡單的邏輯單元來對待,但是仍然可能會包括許多事務分支。一個事務分支與一個到包含在分布式事務中的每個資源管理程序相關聯。因此,到三個不同的關系數據庫管理的請求需要三個事務分支。每個事務分支必須由本地資源管理程序提交或者返回。事務管理程序控制事務的邊界,並且負責最后決定應該提交或者返回的全部事務。這個決定由兩個步驟組成,稱為Two - Phase Commit Protocol。
在第一步驟中,事務管理程序輪詢所有包含在分布式事務中的資源管理程序(關系數據庫管理)來看看哪個可以准備提交。如果一個資源管理程序不能提交,它將不響應,並且把事務的特定部分返回,以便數據不被修改。
在第二步驟中,事務管理程序判斷否定響應的資源管理程序中是否有能夠返回整個事務的。如果沒有否定響應的話,翻譯管理程序提交整個事務並且返回結果到應用程序中。
開發事項管理程序代碼的開發者必須與所有三個JTA接口有關:UserTransaction、TransactionManager和XAResource,這三個接口都被描述在
Sun JTA specification中。JDBC驅動程序開發者只需要關心XAResource接口。這個接口是允許一個資源管理程序參與事務的行業標准X/OpenXA協議的Java映射。連接XAResource接口的驅動程序組件負責在事務管理程序和資源管理程序之間擔任"翻譯"的任務。
3、容器事務
容器事務主要是J2EE應用服務器提供的,容器事務大多是基於JTA完成,這是一個基於JNDI的,相當復雜的API實現。相對編碼實現JTA事務管理,我們可以通過EJB容器提供的容器事務管理機制(CMT)完成同一個功能,這項功能由J2EE應用服務器提供。這使得我們可以簡單的指定將哪個方法加入事務,一旦指定,容器將負責事務管理任務。這是我們土建的解決方式,因為通過這種方式我們可以將事務代碼排除在邏輯編碼之外,同時將所有困難交給J2EE容器去解決。使用EJB CMT的另外一個好處就是程序員無需關心JTA API的編碼,不過,理論上我們必須使用EJB。
四、三種事務差異
1、JDBC事務控制的局限性在一個數據庫連接內,但是其使用簡單。
2、JTA事務的功能強大,事務可以跨越多個數據庫或多個DAO,使用也比較復雜。
3、容器事務,主要指的是J2EE應用服務器提供的事務管理,局限於EJB應用使用。
五、總結
事務控制是構建J2EE應用不可缺少的一部分,合理選擇應用何種事務對整個應用系統來說至關重要。一般說來,在單個JDBC 連接連接的情況下可以選擇JDBC事務,在跨多個連接或者數據庫情況下,需要選擇使用JTA事務,如果用到了EJB,則可以考慮使用EJB容器事務。
在weblogic在對幾種JTA的應用場景進行的測試,總結如下:
測試代碼片段:
public void doTest()throws Exception{
UserTransaction tx = null;
try{
Context ctx = new InitialContext();
tx =(UserTransaction)ctx.lookup("javax.transaction.UserTransaction");
tx.begin();
doResource1();
doResource2();
tx.commit();
}catch(Exception e){
e.printStackTrace();
if(tx != null){
tx.rollback();
}
}
}
private voiddoResource1()throws Exception{
...
DataSourceds = (DataSource)ctx.lookup("A|B|C|D|E");
con =ds.getConnection();
...
}
private voiddoResource2()throws Exception{
...
DataSourceds = (DataSource)ctx.lookup("A|B|C|D|E");
con =ds.getConnection();
...
}
共創建了五個連接池以及對應的數據源
A: OracleLocalDataSource
B: OracleLocalDataSource2
C: OracleXADataSource
D: OracleXADataSource2
E: MysqlLocalDataSource
A、B:【oracle.jdbc.driver.OracleDriver】
C、D:【oracle.jdbc.xa.client.OracleXADataSource】
E:【org.gjt.mm.mysql.Driver】
對於doResource1和doResource2所用不同數據源類型搭配測試情況如下:
[A-A]:運行成功,且weblogic進行了優化,兩次操作獲得的con其實是同一個連接對象
[A-B]:運行失敗,不允許在一次事務中從不同的數據庫獲取local事務類型的連接
[A-E]:運行失敗,不允許在一次事務中從不同的數據庫獲取local事務類型的連接
[A-D]:在允許Emulate Two-Phase Commit for non-XA Driver的情況下成功,否則失敗
[C-C]:運行成功,但是不像(A-A)的情況,兩次獲得con的對象不是同一個對象,weblogic並為對該情況進行優化
[C-D]:運行成功,這是典型的2PC(two-phase transaction commitprocess)用於分布式多資源的應用情況
對於C、D的XA類型驅動程序,weblogic默認不允許通過con.setAutoCommit(false)的方式進行事務啟動,可以通過允許(SupportsLocal Transaction)選項啟動本地事務。
記得EJB的部署文件的事務屬性<trans-attribute>RequiresNew</trans-attribute>的情況,在調用該EJB函數時如果已經存在一個事務進行中,那么要求容器掛起該事務,啟動新的事務進行函數調用,直到函數結束后,再恢復原來的事務繼續進行。
也許你會想到用以下的方式進行:
UserTransaction tx =(UserTransaction)ctx.lookup("javax.transaction.UserTransaction");
UserTransaction tx2 = (UserTransaction)ctx.lookup("javax.transaction.UserTransaction");
tx.begin();
tx2.begin();
tx2.commit();
tx.commit();
以上代碼會拋出如下異常:
javax.transaction.NotSupportedException: Another transaction is associated withthis thread.
查找了sun的 JTA specification 說明如下:
The UserTransaction.begin method starts a global transaction and associates thetransaction with the calling thread. The transaction-to-thread association ismanaged transparently by the Transaction Manager. Support for nestedtranactions is not required. The UserTransaction.begin method throws theNotSupportedException when the calling thread is already associated with atransaction and the transaction manager implementation does not support nestedtransactions.
看來weblogic的Transaction沒有實現嵌套功能,那么容器如何RequiresNew的ejb事務情況呢,就得借助於TransactionManager類了
tm =(TransactionManager)ctx.lookup("javax.transaction.TransactionManager");
tx = (UserTransaction)ctx.lookup("javax.transaction.UserTransaction");
tx.begin();
...
transaction = tm.suspend();
doNestedTransaction();
tm.resume(transaction);
...
tx.commit();
其實以上問題的順利解決都歸功於sun完整的官方資料,想想從事Java快兩年了我的大部分知識都是來源於“東拼西湊”:書籍、論壇、項目...看來是該花點時間好好讀讀sun網站的各種specification了。
今天對XA和非XA驅動進行了更進一步的研究,終於搞清了以前些模菱兩可的問題。
通過測試得知,在JTA事務中(包括JDBC事務以及非事務環境下),應用程序操作的connection其實都是weblogic的包裝類
weblogic.jdbc.wrapper.JTSConnection_weblogic_jdbc_oracle_OracleConnection
weblogic.jdbc.wrapper.JTAConnection_weblogic_jdbc_wrapper_XAConnection_weblogic_jdbcx_base_BaseConnectionWrapper
weblogic.jdbc.wrapper.JTSConnection_com_mysql_jdbc_Connection
由於XA驅動實現了XAResource的接口,所以能參與完全的2PC協議,保證多資源參與的事務的原子操作。但是非XA驅動沒有實現XAResource的接口的接口,無法完全參與2PC協議,所以在分布式事務(即JTA事務)中weblogic實現了非XA驅動的XAResource包裝(wrapper),用來模擬(或者說欺騙TM^_^)兩步提交,在...\bea\weblogic81\server\lib\weblogic.jar類包中,通過反編譯weblogic.jdbc.wrapper.JTSConnection和weblogic.jdbc.wrapperJTSXAResourceImpl類得到如下代碼片段:
JTSXAResourceImpl源碼片段:
public int prepare(Xid xid)throws XAException
{
if(!jtsConn.getEnable2PC())
throw newXAException("JDBC driver does not support XA ... );
else
return 0;
}
public voidcommit(Xid xid, boolean flag)throws XAException
{
...
jtsConn.internalCommit();
...
}
public void rollback(Xid xid)throws XAException
{
...
jtsConn.internalRollback();
...
}
JTSConnection源碼片段:
public synchronized void internalRollback() throwsSQLException
{
...
connection.rollback();
...
internalClose();
...
}
public voidinternalCommit() throws SQLException
{
...
connection.commit();
...
internalClose();
...
}
可知如果非XA驅動允許兩步提交時(enableTwoPhaseCommit),當TransactionManager調用prepare時XAResource包裝類只是簡單的返回XA_OK(0),當TransactionManager調用commit或rollback時XAResource包裝類將代理調用非XA驅動的JDBC connection的commit或rollback,所以如果在commit或rollback出現異常后,應用程序的數據將有可能處於不一致的狀態(其實如果XA驅動在TM調用XAResource的commit或者rollback時出錯,系統數據也會處於不一致的狀態,不過出現這種情況的概率是微乎其微的,如果想搞三步、四步...提交的話,就會進入雞生蛋、蛋生雞的無休止討論的問題了^_^)。
接下來讓我們研究一下連接關閉的問題,細心的人也許早已發現JTA與JDBC的事務對於應用層的操作有點“自相矛盾”,JDBC的先獲得con在setAutoCommit(false)啟動事務,然后關閉con,在commit或者rollback事務,然而JTA的順序正好相反,先tx.begin(),再獲取con,然后關閉con,最后再tx.commit或者rollback。(這里有句話您看完一下內容后會認同的:For both non-XAand XA driver, you can close the connection after the distributed transactionis completed.)
當應用程序調用Connection.close時容器通過注冊的ConnectionEventListener事件通知TransactionManager,以便TransactionManager結束Connection對應的XAResource對象的事務分支(end函數調用),對於XA驅動的連接此時在Connection.close之后即可將該連接返回XA連接池供其他業務使用。
所以JTA spec中的提示到:
A distributed transaction maystill be active after a participating Connection object is closed. This is nottrue for local transactions。
但是對於非XA驅動調用Connection.close后的情況將有所有區別,由於XA驅動需要用connection進行最后的commit或rollback,所以應用程序調用Connection.close之后只是對與應用不能再使用包裝的Connection,但容器並沒有真正將連接返回連接池,而是在調用XAResource包裝類的commit和rollback時,進而調用JTSConnection的internalCommit和internalRollback,最終再JTSConnection的這兩個函數中internalClose將非XA的連接釋放到連接池中。
所以weblogic的資料(http://edocs.bea.com/wls/docs60/faq/transactions.html)中說:
the number of active distributed transactions using the non-XA
connection pool is limited by the maximum capacity of the JDBC connection pool
When you use an XA driver, theconnection management is more scalable. WLS does not hold on to the same physicalXA connection until the transaction is committed or rolled back. In fact, inmost cases, the XA connection as only held for the duration of a methodinvocation. WLS JDBC wrappers intercept all JDBC calls and enlist theXAResource associated with the XA connection on demand. When the methodinvocation returns to the caller, or when it makes another call to anotherserver, WLS delists the XAResource associated with the XA connection.
WLS also returns the XA connectionto the connection pool on delistment if there are no open result sets. Also,during commit processing, any XAResource object can be used to commit anynumber of distributed transactions in parallel. As a result, neither the numberof active distributed transactions using the XA connection pool nor the numberof concurrent commit/rollbacks is limited by the maximum capacity of theconnection pool. Only the number of concurrent database access connections islimited by the maximum capacity of the connection pool.
對於以上XA驅動的con在關閉后,不必等待事務結束即釋放回連接池的推論,我在weblogic上對oracle做了些好像沒有效果,weblogic中有個 Keep XA Connection Till Transaction Complete 的選項我也沒有選中啊。不知是我對JTA的理解有誤,還是說與我用的數據庫驅動或者是weblogic的實現有關,有時間要好好研究一下了。
最后請注意:除非將XA驅動的連接池設置允許【Supports Local Transaction】選項,否則在非事務的環境下對con進行的操作將拋出如下錯誤,甚至是getAutoCommit()操作
剛看完《hibernate in action》,前段時間hiberante3又發布了3.0.2版,對於hibernate的這種更新路線我還是比較喜歡的,2.x的版本繼續更新發展這對於已經在項目中應用hibernate的人來說是再慶幸不過的了(不過這也許是廢話,如果GAVIN KING不繼續發展2.x誰還敢用3.x,因為...4.x...),3版本是不兼容2的,整體包名都進行了徹底的變動,如果想移植的話其實工作量也不大很多接口都是一樣的,配置文件也盡量保持以前的規范,而且3會有更多令人興奮的新特性,這種走不同版本分支、不拖泥帶水的革新,至少讓我感覺比一味堅持要兼容老版本的EJB3來得爽!
下面我還來講講hibernate中的JTA事務應用。
本人對於hibernate我還是比較喜歡的,特別是在領域驅動設計開發,完全消除了面向對象與面向關系(數據庫)的抗阻,真的很爽,(不是很喜歡老的開發方法,一開始就分析系統有多少個實體,有多少數據表)
//////////////以下為hibernate中的經典事務操作步驟 //////////////
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
}
hibernate2中只有JDBCTransaction和JTATransaction兩種事務類,對於使用JTA事務的應用,
應該說JTATransaction適用於絕大部分情況,但是CMT情況將存在一些例外:
////////// begin片段 //////////
newTransaction = ut.getStatus() ==Status.STATUS_NO_TRANSACTION;
if (newTransaction) {
ut.begin();
log.debug("Began a new JTA transaction");
}
////////// commit片段 //////////
if (session.getFlushMode()!=FlushMode.NEVER ) session.flush();
if (newTransaction) {
try {
log.debug("Committing UserTransaction started by Hibernate");
ut.commit();
}
////////// rollback片段 //////////
if (newTransaction) {
if (!commitFailed) ut.rollback();
}
else {
ut.setRollbackOnly();
}
通過以上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中的代碼片段可以改造如下:
Session sess =factory.openSession();
try {
// do some work
...
session.flush();
}
catch (RuntimeException e) {
context.setRollbackOnly();
throw e; // or display error message
}
finally {
sess.close();
}
為了解決以上問題hibernate3進行了改進,增加了CMTTransaction類,以及兩個新屬性:
1:【hibernate.transaction.flush_before_completion】
If enabled, the session will be automatically flushed during the beforecompletion
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 beforecompletion
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()。
最后一點需要注意的是數據庫事務隔離級別的設置:
----------------------------------------------------------------
■ Readuncommitted:
這個級別是不安全的,事務中的查詢會讀到當前其它事務正在設置當時還未提交的數據
■ Readcommitted:
這個級別相對比較安全,事務中讀到的數據都是已經得到提交的數據,但是如果兩次讀取同一個條記錄,但是在兩次讀取的過程中有另外的事務更改了改記錄並成功提交的話,則會出現同一事務中兩次讀取同一條記錄數據不一致的情況。這種情況很少出現,因為一般同一事務的程序不會重復讀取同一條記錄,如果用hibernate就更安全了,hibernate的一級緩存不會讓程序向數據庫兩次讀取同一條記錄。
■ Repeatable read:
這個級別解決了同一事務兩次讀取數據結果不同的情況,這個級別也是很多數據庫的默認事務級別(如mysql)
■Serializable:
這個級別會使所有事務串行化工作,每個事務只能排隊進行數據庫操作,類似單線程的Servlet的工作機制,這樣在並非量較高的數據庫訪問時,數據庫操作效率將極其底下,應該避免使用
----------------------------------------------------------------
hibernate中通過【hibernate.connection.isolation】屬性進行設置,但是如果hibernate的數據庫連接是通過數據源獲得的話,hibernate則不再對事務隔離級別進行設置,所以對於數據源的到的數據庫連接只能通過設置應用服務器配置數據庫隔離級別,當然也可以通過Connection con=session.connection();con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);進行手工設置。