晚上要下班的時候,application team那裡使用Tibco EMS做消息集成服務時候出了bug,錯誤是: java.sql.SQLException: 當全局事務處理處於活動狀態時, 無法調用方法 'commit',應該是在全局事務 中使用了本地事務並提交了。幫忙看了一下,它的oc4j, toplink, spring的使用上都存在著一些問題, 並把要注意的地方總結了一下。
Jta外部事務,也稱為分布式事務,全局事務。
oc4j:
·讓transaction manager知道resource的存在
要使用外部事務,首先要讓transaction manager了解是哪個resource。我們選擇使用managed resource,這樣由容器來管理:data source, jms resouce, jca resource,oc4j的transaction manager 肯定是知道這些managed resource的存在的,可以通過ra,data-sources.xml來配置,或者直接通過oc4j web console來創建。
Oc4j data-sources.xml
特別要注意的是data source的設置,oc4j中可以通過data-sources.xml設置transaction level,默 認是global,表示join jta外部事務,如果是local,oc4j就會把所有的managed datasource的操作當作 local connection來看待,這些操作是不join到外部事務中的。
什麼是一次local transaction操作呢?
Toplink:每次對unitofwork的提交。
Connection的每次提交,auto commit的每次操作。
<managed-data-source name="MIFSystemLogDataSource"
connection-pool-name="MIFSysLogConnectionFactory"
jndi-name="jdbc/mifStatusLog" tx-level='global'/>
有人會問沒有使用xa的connection怎麼能使用外部事務join transaction呢,oracle實現了稱為 Emulating XA(oc4j container),它基本上模擬了two phase commit的功能,但是沒有transaction branches,也就是xid的branch標識符,xid包括format標識符, global事務標識符和branch標識符。也 沒有two phase commit的預提交過程。Toplink在使用session broker時,也有類似的配置,稱為two stage commit。xa的resource應該配置成global的transaction,否則沒必要用xa。
Oc4j中如何自己控制transaction
有時我們可能需要自己控制transaction,這樣我們可能需要在oc4j中獲得受管的UserTransaction和 TransactionManager,TransactionManager可以suspend和resume一個transaction,實現諸如requires new這樣的功能。
Context initialContext = new InitialContext();
UserTransaction userTrx = (javax.transaction.UserTransaction) initialContext.lookup("java:comp/UserTransaction");
if (ut instanceof TransactionManager) {
TransactionManager tm = (TransactionManager) userTrx;
}
如果使用的是分布式全局transaction不建議在程序中調用connection.setAutoCommit(true), connection.commit(), commit.rollback()方法,這樣會干擾分布式事務的管理。
2.Toplink
如果toplink需要跨多個data source,請使用session broker
<session>
<name>EmployeeSession</name>
...
</session>
<session>
<name>ProjectSession</name>
...
</session>
/* Configure the SessionBroker */
<session-broker>
/* Name the SessionBroker */
<name>EmployeeAndProjectBroker</name>
/* Specify the sessions contained in the SessionBroker */
<session-name>EmployeeSession</session-name>
<session-name>ProjectSession</session-name>
</session-broker>
如果toplink的操作想join到外部事務,或者說使用two phase commit,需要在session中激活使用是 用外部事務,可以通過sessions.xml配置:
<external-transaction-controller>true</external-transaction-controller>
3.Spring
使用外部事務
<bean name="transactionManager"
class="org.springframework.transaction.jta.OC4JJtaTransactionManager" >
</bean>
或者
<bean name="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager" >
</bean>
本地事務
<bean name="transactionManager"
class=" org.springframework.orm.toplink. TopLinkTransactionManager " >
<property name="sessionFactory" ref="sessionFactory" />
</bean>