使用Atomikos Transactions Essentials实现多数据源JTA分布式事务

使用Atomikos Transactions Essentials实现多数据源JTA分布式事务

9.17 update:使用NonXADataSourceBean. Mysql在5.0版本和Connecter/J5.0版本后提供了XADatasource支持,如果使用了支持XADatasouce版本,可以参考2楼补充. 

最近做的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配置文件如下:

xml 代码
 
  1. <!-- 第一个数据库 -->   
  2. < bean   id = "dataSource"   class = "com.atomikos.jdbc.SimpleDataSourceBean"   init-method = "init"   destroy-method = "close" >   
  3.     < property   name = "uniqueResourceName" >   
  4.         < value > mysql/main </ value >   
  5.     </ property >   
  6.     < property   name = "xaDataSourceClassName" >   
  7.         <!-- 使用Mysql XADataSource(mysql>=5.0, Connector/J>=5.0才可以支持XADatasource)-->   
  8.         < value > com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </ value >   
  9.     </ property >   
  10.     < property   name = "xaDataSourceProperties" >   
  11.         < value > URL =${jdbc.url}; user =${jdbc.username}; password =${jdbc.password} </ value >   
  12.     </ property >   
  13.     < property   name = "exclusiveConnectionMode" >   
  14.         < value > true </ value >   
  15.     </ property >   
  16.     < property   name = "connectionPoolSize" >   
  17.         < value > 3 </ value >   
  18.     </ property >   
  19.     < property   name = "validatingQuery" >   
  20.         < value > SELECT 1 </ value >   
  21.     </ property >   
  22. </ bean >   
  23. <!-- 第二个数据库 -->   
  24. < bean   id = "dataSourceB"   class = "com.atomikos.jdbc.SimpleDataSourceBean"   init-method = "init"   destroy-method = "close" >   
  25.     < property   name = "uniqueResourceName" >   
  26.         < value > mysql/news </ value >   
  27.     </ property >   
  28.     < property   name = "xaDataSourceClassName" >   
  29.         <!-- 使用Mysql XADataSource(mysql>=5.0, Connector/J>=5.0才可以支持XADatasource)-->   
  30.         < value > com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </ value >   
  31.     </ property >   
  32.     < property   name = "xaDataSourceProperties" >   
  33.         < value > URL =${jdbc.url.b}; user =${jdbc.username.b}; password =${jdbc.password.b} </ value >   
  34.     </ property >   
  35.     < property   name = "exclusiveConnectionMode" >   
  36.         < value > true </ value >   
  37.     </ property >   
  38.     < property   name = "connectionPoolSize" >   
  39.         < value > 3 </ value >   
  40.     </ property >   
  41.     < property   name = "validatingQuery" >   
  42.         < value > SELECT 1 </ value >   
  43.     </ property >   
  44. </ bean >   
  45.   
  46.   
  47. < bean   id = "lobHandler"   class = "org.springframework.jdbc.support.lob.DefaultLobHandler"   />   
  48.   
  49. <!-- 第一个数据库的sqlMapClient -->   
  50. < bean   id = "sqlMapClient"   class = "org.springframework.orm.ibatis.SqlMapClientFactoryBean" >   
  51.     < property   name = "configLocation" >   
  52.         <!-- 包含第一个数据库表的map -->   
  53.         < value > classpath:/sqlmap-config.xml </ value >   
  54.     </ property >   
  55.     < property   name = "dataSource"   ref = "dataSource"   />   
  56.     < property   name = "lobHandler"   ref = "lobHandler"   />   
  57. </ bean >   
  58. <!-- 第二个数据库的sqlMapClient -->   
  59. < bean   id = "sqlMapClientB"   class = "org.springframework.orm.ibatis.SqlMapClientFactoryBean" >   
  60.     < property   name = "configLocation" >   
  61.         <!-- 包含第一个数据库表的map -->   
  62.         < value > classpath:/sqlmap-configb.xml </ value >   
  63.     </ property >   
  64.     < property   name = "dataSource"   ref = "dataSourceB"   />   
  65.     < property   name = "lobHandler"   ref = "lobHandler"   />   
  66. </ bean >   
  67.   
  68. <!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->   
  69. < bean   id = "atomikosTransactionManager"   class = "com.atomikos.icatch.jta.UserTransactionManager"   init-method = "init"   
  70.     destroy-method = "close" >   
  71.     <!--  when close is called, should we force transactions to terminate or not? -->   
  72.     < property   name = "forceShutdown" >   
  73.         < value > true </ value >   
  74.     </ property >   
  75. </ bean >   
  76.   
  77. <!-- Also use Atomikos UserTransactionImp, needed to configure Spring  -->   
  78. < bean   id = "atomikosUserTransaction"   class = "com.atomikos.icatch.jta.UserTransactionImp" >   
  79.     < property   name = "transactionTimeout"   value = "240"   />   
  80. </ bean >   
  81.   
  82. <!-- Configure the Spring framework to use JTA transactions from Atomikos -->   
  83. < bean   id = "transactionManager"   class = "org.springframework.transaction.jta.JtaTransactionManager" >   
  84.     < property   name = "transactionManager" >   
  85.         < ref   bean = "atomikosTransactionManager"   />   
  86.     </ property >   
  87.     < property   name = "userTransaction" >   
  88.         < ref   bean = "atomikosUserTransaction"   />   
  89.     </ property >   
  90. </ bean >   



事务的配置, 使用了spring2.0的语法,所以将namesapce也帖出来了.

xml 代码
 
  1. <? xml   version = "1.0"   encoding = "UTF-8" ?>   
  2. < beans   xmlns = "http://www.springframework.org/schema/beans"   
  3.        xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"   
  4.        xmlns:aop = "http://www.springframework.org/schema/aop"   
  5.        xmlns:tx = "http://www.springframework.org/schema/tx"   
  6.        xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
  7.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd  
  8.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"  
  9.        default-autowire = "byName"   default-lazy-init = "true" >   
  10.     <!-- 支持 @AspectJ 标记-->   
  11.     < aop:aspectj-autoproxy />   
  12.   
  13.     < aop:config   proxy-target-class = "true" >   
  14.         < aop:advisor   pointcut = "execution(* *Facade.*(..))"   advice-ref = "txAdvice" />   
  15.         < aop:advisor   pointcut = "execution(* *Manager.*(..))"   advice-ref = "txAdvice" />   
  16.     </ aop:config >   
  17.   
  18.     < tx:advice   id = "txAdvice" >   
  19.         < tx:attributes >   
  20.             < tx:method   name = "get*"   read-only = "true" />   
  21.             < tx:method   name = "find*"   read-only = "true" />   
  22.             < tx:method   name = "has*"   read-only = "true" />   
  23.             < tx:method   name = "locate*"   read-only = "true" />   
  24.             < tx:method   name = "*" />   
  25.         </ tx:attributes >   
  26.     </ tx:advice >   
  27. </ beans >   


这样配置以后就可以使用分布式事务,测试中出现异常时事务也自动提交。和JOTM相比Atomikos Transactions Essentials更加稳定,它原来是商业项目,现在开源了。象mysql一样卖服务支持的。而且论坛页比较活跃,有问题很快可以解决。

1 楼 andyao 2007-09-10  
使用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>
2 楼 andyao 2007-09-17  
andyao 写道
core里面怎么有这么多span,编辑的时候没有。

已经修改好
3 楼 away5678 2007-09-30  
不用SPRING2.0配置方法行吗
4 楼 andyao 2007-10-08  
不用Spring也可以,直接编程使用.
5 楼 81261686 2007-11-25  
我也使用了Atomikos Transactions做分布式事务,tomcat+hibernate+spring,事务能成功rollback,便在停tomcat时候老是有
错,错误信息如下:
Exception in thread "Thread-14" java.lang.NullPointerException
at com.atomikos.icatch.system.Configuration.removeResource(Unknown Source)
at com.atomikos.jdbc.JtaDataSourceImp.close(Unknown Source)
at com.atomikos.jdbc.DataSourceShutdownHook.run(Unknown Source)
Exception in thread "Thread-6" java.lang.NullPointerException
at com.atomikos.icatch.system.Configuration.removeResource(Unknown Source)
at com.atomikos.jdbc.JtaDataSourceImp.close(Unknown Source)
at com.atomikos.jdbc.DataSourceShutdownHook.run(Unknown Source)
Unknown Source倒底是什么指资源?
6 楼 andycui 2008-01-08  
我最近也用JOTM做JTA,也发现不能rollback oracle数据库,后来发现使用的datasource是C3P0,好像C3P0是不支持XADATASOURCE的,后来我把C3P0换成XAPOOL,发现一切OK,能回滚了,查了C3P0的官方文档,发现它仅仅只是说它是对JDBC3和JDBC2的一些补充,没有提及XADATASOURCE方面的东西,估计就是不支持,我不确定
7 楼 andyao 2008-01-10  
andycui 写道
我最近也用JOTM做JTA,也发现不能rollback oracle数据库,后来发现使用的datasource是C3P0,好像C3P0是不支持XADATASOURCE的,后来我把C3P0换成XAPOOL,发现一切OK,能回滚了,查了C3P0的官方文档,发现它仅仅只是说它是对JDBC3和JDBC2的一些补充,没有提及XADATASOURCE方面的东西,估计就是不支持,我不确定

C3P0不支持XADatasource.

而且使用数据库的时候也要使用数据库的XA驱动
8 楼 baoyaer 2008-06-18  
Caused by: com.atomikos.icatch.SysException: Error in init(): Log already in use?
[17:03:01.375] at com.atomikos.icatch.standalone.UserTransactionServiceImp.init(Unknown Source)
[17:03:01.375] at com.atomikos.icatch.config.UserTransactionServiceImp.init(Unknown Source)
[17:03:01.375] at com.atomikos.icatch.jta.UserTransactionManager.checkSetup(Unknown Source)
[17:03:01.375] at com.atomikos.icatch.jta.UserTransactionManager.init(Unknown Source)
[17:03:01.375] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[17:03:01.375] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[17:03:01.375] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[17:03:01.375] at java.lang.reflect.Method.invoke(Method.java:597)
[17:03:01.375] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1240)
[17:03:01.375] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1205)
[17:03:01.375] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1171)
[17:03:01.375] ... 90 more




这个错误难道各位都没遇到?奇了怪!这个问题在3.1之前是个bug,作者后来说要修复,但是我在3.2,3.3中都碰到了
9 楼 bagui3 2008-07-15  
引用
Caused by: com.atomikos.icatch.SysException: Error in init(): Log already in use? 
[17:03:01.375] at com.atomikos.icatch.standalone.UserTransactionServiceImp.init(Unknown Source) 
[17:03:01.375] at com.atomikos.icatch.config.UserTransactionServiceImp.init(Unknown Source) 
[17:03:01.375] at com.atomikos.icatch.jta.UserTransactionManager.checkSetup(Unknown Source) 
[17:03:01.375] at com.atomikos.icatch.jta.UserTransactionManager.init(Unknown Source) 
[17:03:01.375] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
[17:03:01.375] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
[17:03:01.375] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
[17:03:01.375] at java.lang.reflect.Method.invoke(Method.java:597) 
[17:03:01.375] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1240) 
[17:03:01.375] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1205) 
[17:03:01.375] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1171) 
[17:03:01.375] ... 90 more 
这个错误难道各位都没遇到?奇了怪!这个问题在3.1之前是个bug,作者后来说要修复,但是我在3.2,3.3中都碰到了
删掉项目里面的一个tm***.lck文件就可以了







Atomikos分两个:一个是开源的TransactionEssentials,一个是商业的ExtremeTransactions。
TransactionEssentials的主要特征:JTA/XA 事务管理 —— 提供事务管理和连接池不需要应用服务器 —— TransactionEssentials可以在任何Java EE应用服务器中运行,也就是不依赖于任何应用服务器开源 —— TransactionEssentials是遵守Apache版本2许可的开源软件专注于JDBC/JMS —— 支持所有XA资源,但是资源池和消息监听是专供JDBC和JMS的与Spring 和 Hibernate 集成 —— 提供了描述如何与Spring和Hibernate集成的文档
一、环境

spring 2

ibatis2

AtomikosTransactionsEssentials-3.7.0 下载地址:http://www.atomikos.com/Main/InstallingTransactionsEssentials

MySQL-5.1 :数据库引擎为InnoDB,只有这样才能支持事务 

JDK1.6

Oracle10


二 jar包

 Atomikos jar必须包 transactions-jdbc.jar

transactions-jta.jar

transactions.jar

atomikos-util.jar  

transactions-api.jar 

ibatis,spring

只要符合二者集成jar组合即可,无额外jar

三、配置

Oracle用户授权:(视情况而定,如果程序出现如下异常则需要加上1672 [main] WARN atomikos - ERROR IN RECOVERY com.atomikos.datasource.ResourceException: Error in recovery)

grant select on sys.dba_pending_transactions to orcl;

grant select on sys.pending_trans$ to orcl;

grant select on sys.dba_2pc_pending to orcl;

grant execute on sys.dbms_system to orcl;


jta.properties 配置文件,即src/ jta.properties内容如下:

 

?
1
2
3
4
5
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
  com.atomikos.icatch.console_file_name = tm.out
com.atomikos.icatch.log_base_name = tmlog
com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
com.atomikos.icatch.console_log_level = INFO   

 

 


spring配置文件

复制代码
代码
         
         
<? 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 " > <!-- 事物管理器 --> < bean id ="atomikosUserTransaction" class ="com.atomikos.icatch.jta.UserTransactionImp" > < description > UserTransactionImp </ description > < property name ="transactionTimeout" value ="300" /> </ bean > < bean id ="atomikosTransactionManager" class ="com.atomikos.icatch.jta.UserTransactionManager" init-method ="init" destroy-method ="close" > < description > UserTransactionManager </ description > < property name ="forceShutdown" > < value > true </ value > </ property > </ bean > < bean id ="transactionManager" class ="org.springframework.transaction.jta.JtaTransactionManager" > < description > JtaTransactionManager </ description > < property name ="transactionManager" > < ref bean ="atomikosTransactionManager" /> </ property > < property name ="userTransaction" > < ref bean ="atomikosUserTransaction" /> </ property > < property name ="allowCustomIsolationLevels" value ="true" /> <! —必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -- > <! —oracle数据源定义 -- > </ bean > < bean id ="oracleDS" class ="com.atomikos.jdbc.AtomikosDataSourceBean" init-method ="init" destroy-method ="close" > < description > oracle xa datasource </ description > < property name ="uniqueResourceName" > < value > oracle_ds </ value > </ property > < property name ="xaDataSourceClassName" > < value > oracle.jdbc.xa.client.OracleXADataSource </ value > </ property > < property name ="xaProperties" > < props > < prop key ="user" > orcl </ prop > < prop key ="password" > 123 </ prop > < prop key ="URL" > jdbc:oracle:thin:@ localhost:1521:orcl </ prop > </ props > </ property > < property name ="testQuery" > < value > select 1 from dual </ value > <! —尽力加上,不然会出现告警 -- > </ property > </ bean > <! — mysql数据源定义 -- > < bean id ="dataSourceoracle2" class ="com.atomikos.jdbc.AtomikosDataSourceBean" init-method ="init" destroy-method ="close" > < description > mysql xa datasource </ description > < property name ="uniqueResourceName" > < value > mysql_ds </ value > </ property > < property name ="xaDataSourceClassName" > < value > com.mysql.jdbc.jdbc2.optional.MysqlXADataSource </ value > </ property > < property name ="xaProperties" > < props > < prop key ="user" > root </ prop > < prop key ="password" > 123 </ prop > < prop key ="URL" > jdbc:mysql://localhost:3306/test?useUnicode=true &amp; characterEncoding=utf-8 </ prop > </ props > </ property > < property name ="testQuery" > < value > select 1 </ value > <! —尽力加上,不然会出现告警 -- > </ property > </ bean > <!-- ibatis配置源 --> < bean id ="sqlMapClient" class ="org.springframework.orm.ibatis.SqlMapClientFactoryBean" > < property name ="configLocation" value ="classpath:sql-moredata-config.xml" /> < property name ="dataSource" ref ="oracleDS" /> </ bean > <!-- ibatis配置源2 --> < bean id ="sqlMapClient2" class ="org.springframework.orm.ibatis.SqlMapClientFactoryBean" > < property name ="configLocation" value ="classpath:sql-moredata2-config.xml" /> < property name ="dataSource" ref ="dataSourceoracle2" /> </ bean > < bean id ="testDaoR" class ="com.test.moredata.TestDAOImpR" > < property name ="sqlMapClient" ref ="sqlMapClient" ></ property > </ bean > < bean id ="testDao" class ="com.test.moredata.TestDAOImp" > < property name ="sqlMapClient" ref ="sqlMapClient2" ></ property > </ bean > < bean id ="testService" class ="com.test.moredata.TestService" > < property name ="testDao" ref ="testDao" ></ property > < property name ="testDaoR" ref ="testDaoR" ></ property > </ bean > <! — aop配置 -- > < tx:advice id ="transactionManagerAdivice" transaction-manager ="transactionManager" > < tx:attributes > < tx:method name ="*" isolation ="READ_COMMITTED" propagation ="REQUIRED" rollback-for ="java.lang.RuntionException" /> </ tx:attributes > </ tx:advice > < aop:config > < aop:pointcut expression ="execution(* com.test.moredata.TestService.*(..))" id ="tsServicePc" /> < aop:advisor advice-ref ="transactionManagerAdivice" pointcut-ref ="tsServicePc" /> </ aop:config >
复制代码

 


Ok主要的配置就是这样,下面就是自己写下dao,service等


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值