1. 程式人生 > >使用Atomikos Transactions Essentials實現多資料來源JTA分散式事務

使用Atomikos Transactions Essentials實現多資料來源JTA分散式事務

宣告:本片文章來源於開源社群論壇轉載~!奮鬥

使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本後提供了XADatasource支援,如果使用了支援XADatasouce版本

最近做的project中遇到要將資料庫中的表分佈到兩臺不同的伺服器上的Mysql5.0中,project主要使用spring+ibatis。因此需要JTA的支援,但是tomcat不支援,所以就搜尋開源的JTA實現。
最開始使用的是JOTM,但是使用中不能自動rollback,無論什麼情況都commit。然後看到infoq上一篇文章提到Atomikos Transactions Essentials,Atomikos Transactions Essentials 3.0是Atomikos 開發的核心事務引擎,支援JDBC 以及JMS 的JTA/XA 事務。易於部署,輕量級,同時支援JDBC 以及JMS 。
Atomikos Transactions Essentials現在的版本是3.1.7,可以在

http://www.atomikos.com/Main/TransactionsEssentialsDownloadForm 下載,在釋出包裡的examples資料夾下面有些例子,非常實用,我在使用中參考裡面的例子很容易配置成功。先將釋出包裡面dist目錄下的 atomikos-util.jar,transactions.jar,transactions-api.jar,transactions- jta.jar copy到專案lib裡面, 如果使用hibernate則需要將另外兩個hibernate相關的jar也copy到專案裡面,spring:置檔案如下:

<!-- 第一個資料庫 -->
< bean id = "dataSource" class = "com.atomikos.jdbc.SimpleDataSourceBean" init-method = "init" destroy-method = "close" > <property name="uniqueResourceName"> <value> mysql/main </value> </property> <property name = "xaDataSourceClassName
">
<!-- 使用Mysql XADataSource(mysql>=5.0, Connector/J>=5.0才可以支援XADatasource)--> <value > com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </ value > </ property > < property name = "xaDataSourceProperties" > < value > URL =${jdbc.url}; user =${jdbc.username}; password =${jdbc.password} </ value > </ property > < property name = "exclusiveConnectionMode" > < value > true </ value > </ property > < property name = "connectionPoolSize" > < value > 3 </ value > </ property > < property name = "validatingQuery" > < value > SELECT 1 </ value > </ property > </ bean > <!-- 第二個資料庫 --> < bean id = "dataSourceB" class = "com.atomikos.jdbc.SimpleDataSourceBean" init-method = "init" destroy-method = "close" > < property name = "uniqueResourceName" > < value > mysql/news </ value > </ property > < property name = "xaDataSourceClassName" > <!-- 使用Mysql XADataSource(mysql>=5.0, Connector/J>=5.0才可以支援XADatasource)--> < value > com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </ value > </ property > < property name = "xaDataSourceProperties" > < value > URL =${jdbc.url.b}; user =${jdbc.username.b}; password =${jdbc.password.b} </ value > </ property > < property name = "exclusiveConnectionMode" > < value > true </ value > </ property > < property name = "connectionPoolSize" > < value > 3 </ value > </ property > < property name = "validatingQuery" > < value > SELECT 1 </ value > </ property > </ bean > < bean id = "lobHandler" class = "org.springframework.jdbc.support.lob.DefaultLobHandler" /> <!-- 第一個資料庫的sqlMapClient --> < bean id = "sqlMapClient" class = "org.springframework.orm.ibatis.SqlMapClientFactoryBean" > < property name = "configLocation" > <!-- 包含第一個資料庫表的map --> < value > classpath:/sqlmap-config.xml </ value > </ property > < property name = "dataSource" ref = "dataSource" /> < property name = "lobHandler" ref = "lobHandler" /> </ bean > <!-- 第二個資料庫的sqlMapClient --> < bean id = "sqlMapClientB" class = "org.springframework.orm.ibatis.SqlMapClientFactoryBean" > < property name = "configLocation" > <!-- 包含第一個資料庫表的map --> < value > classpath:/sqlmap-configb.xml </ value > </ property > < property name = "dataSource" ref = "dataSourceB" /> < property name = "lobHandler" ref = "lobHandler" /> </ bean > <!-- Construct Atomikos UserTransactionManager, needed to configure Spring --> < bean id = "atomikosTransactionManager" class = "com.atomikos.icatch.jta.UserTransactionManager" init-method = "init" destroy-method = "close" > <!-- when close is called, should we force transactions to terminate or not? --> < property name = "forceShutdown" > < value > true </ value > </ property > </ bean > <!-- Also use Atomikos UserTransactionImp, needed to configure Spring --> < bean id = "atomikosUserTransaction" class = "com.atomikos.icatch.jta.UserTransactionImp" > < property name = "transactionTimeout" value = "240" /> </ bean > <!-- Configure the Spring framework to use JTA transactions from Atomikos --> < bean id = "transactionManager" class = "org.springframework.transaction.jta.JtaTransactionManager" > < property name = "transactionManager" > < ref bean = "atomikosTransactionManager" /> </ property > < property name = "userTransaction" > < ref bean = "atomikosUserTransaction" /> </ property > </ bean >

事務的配置, 使用了spring2.0的語法,所以將namesapce也帖出來了.

<? xml   version = "1.0"   encoding = "UTF-8" ?>   
< beans   xmlns = "http://www.springframework.org/schema/beans"  
       xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:aop = "http://www.springframework.org/schema/aop"  
       xmlns:tx = "http://www.springframework.org/schema/tx"  
       xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"  
       default-autowire = "byName"   default-lazy-init = "true" >   
    <!-- 支援 @AspectJ 標記-->  
    < aop:aspectj-autoproxy />   

    < aop:config   proxy-target-class = "true" >   
        < aop:advisor   pointcut = "execution(* *Facade.*(..))"   advice-ref = "txAdvice" />   
        < aop:advisor   pointcut = "execution(* *Manager.*(..))"   advice-ref = "txAdvice" />   
    </ aop:config >   

    < tx:advice   id = "txAdvice" >   
        < tx:attributes >   
            < tx:method   name = "get*"   read-only = "true" />   
            < tx:method   name = "find*"   read-only = "true" />   
            < tx:method   name = "has*"   read-only = "true" />   
            < tx:method   name = "locate*"   read-only = "true" />   
            < tx:method   name = "*" />   
        </ tx:attributes >   
    </ tx:advice >   
</ beans >

這樣配置以後就可以使用分散式事務,測試中出現異常時事務也自動回滾。和JOTM相比Atomikos Transactions Essentials更加穩定,它原來是商業專案,現在開源了。象mysql一樣賣服務支援的。而且論壇頁比較活躍,有問題很快可以解決。