使用Atomikos Transactions Essentials实现多数据源JTA分布式事务
最近做的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/home.html下载,在发布包里的examples文件夹下面有些例子,非常实用,我在使用中参考里面的例子很容易配置成功。先将发布包里面dist目录下的 atomikos-util.jar,transactions.jar,transactions-api.jar,transactions- jta.jar copy到项目lib里面,如果使用hibernate则需要将另外两个hibernate相关的jar页copy到项目里面,spring配置文件如下:
- <!-- 第一个数据库 -->
- <beanid="dataSource"class="com.atomikos.jdbc.SimpleDataSourceBean"init-method="init"destroy-method="close">
- <propertyname="uniqueResourceName">
- <value>mysql/main</value>
- </property>
- <propertyname="xaDataSourceClassName">
- <!-- 使用Mysql XADataSource(mysql>=5.0, Connector/J>=5.0才可以支持XADatasource)-->
- <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
- </property>
- <propertyname="xaDataSourceProperties">
- <value>URL=${jdbc.url};user=${jdbc.username};password=${jdbc.password}</value>
- </property>
- <propertyname="exclusiveConnectionMode">
- <value>true</value>
- </property>
- <propertyname="connectionPoolSize">
- <value>3</value>
- </property>
- <propertyname="validatingQuery">
- <value>SELECT 1</value>
- </property>
- </bean>
- <!-- 第二个数据库 -->
- <beanid="dataSourceB"class="com.atomikos.jdbc.SimpleDataSourceBean"init-method="init"destroy-method="close">
- <propertyname="uniqueResourceName">
- <value>mysql/news</value>
- </property>
- <propertyname="xaDataSourceClassName">
- <!-- 使用Mysql XADataSource(mysql>=5.0, Connector/J>=5.0才可以支持XADatasource)-->
- <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
- </property>
- <propertyname="xaDataSourceProperties">
- <value>URL=${jdbc.url.b};user=${jdbc.username.b};password=${jdbc.password.b}</value>
- </property>
- <propertyname="exclusiveConnectionMode">
- <value>true</value>
- </property>
- <propertyname="connectionPoolSize">
- <value>3</value>
- </property>
- <propertyname="validatingQuery">
- <value>SELECT 1</value>
- </property>
- </bean>
- <beanid="lobHandler"class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>
- <!-- 第一个数据库的sqlMapClient -->
- <beanid="sqlMapClient"class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <propertyname="configLocation">
- <!-- 包含第一个数据库表的map -->
- <value>classpath:/sqlmap-config.xml</value>
- </property>
- <propertyname="dataSource"ref="dataSource"/>
- <propertyname="lobHandler"ref="lobHandler"/>
- </bean>
- <!-- 第二个数据库的sqlMapClient -->
- <beanid="sqlMapClientB"class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <propertyname="configLocation">
- <!-- 包含第一个数据库表的map -->
- <value>classpath:/sqlmap-configb.xml</value>
- </property>
- <propertyname="dataSource"ref="dataSourceB"/>
- <propertyname="lobHandler"ref="lobHandler"/>
- </bean>
- <!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->
- <beanid="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? -->
- <propertyname="forceShutdown">
- <value>true</value>
- </property>
- </bean>
- <!-- Also use Atomikos UserTransactionImp, needed to configure Spring -->
- <beanid="atomikosUserTransaction"class="com.atomikos.icatch.jta.UserTransactionImp">
- <propertyname="transactionTimeout"value="240"/>
- </bean>
- <!-- Configure the Spring framework to use JTA transactions from Atomikos -->
- <beanid="transactionManager"class="org.springframework.transaction.jta.JtaTransactionManager">
- <propertyname="transactionManager">
- <refbean="atomikosTransactionManager"/>
- </property>
- <propertyname="userTransaction">
- <refbean="atomikosUserTransaction"/>
- </property>
- </bean>
事务的配置, 使用了spring2.0的语法,所以将namesapce也帖出来了.
- <?xmlversion="1.0"encoding="UTF-8"?>
- <beansxmlns="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:configproxy-target-class="true">
- <aop:advisorpointcut="execution(* *Facade.*(..))"advice-ref="txAdvice"/>
- <aop:advisorpointcut="execution(* *Manager.*(..))"advice-ref="txAdvice"/>
- </aop:config>
- <tx:adviceid="txAdvice">
- <tx:attributes>
- <tx:methodname="get*"read-only="true"/>
- <tx:methodname="find*"read-only="true"/>
- <tx:methodname="has*"read-only="true"/>
- <tx:methodname="locate*"read-only="true"/>
- <tx:methodname="*"/>
- </tx:attributes>
- </tx:advice>
- </beans>
这样配置以后就可以使用分布式事务,测试中出现异常时事务也自动提交。和JOTM相比Atomikos Transactions Essentials更加稳定,它原来是商业项目,现在开源了。象mysql一样卖服务支持的。而且论坛页比较活跃,有问题很快可以解决。
使用XADatasource的数据源配置
- <!-- 第一个数据库 -->
- <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>