最近在做一套底层数据同步对接程序,项目要求将同一笔业务数据分别在多个不同系统间流转,在这个过程中数据需要实时的跨越多个不同种类的数据库。因为觉得具有一定的代表性,所以特将此次demo程序开发过程摘录关键之处与大家共同分享。
因为之前对分布式事物了解不多,最初在网上找了些资料发现jotm(jta的开源实现)相关的文章和资料很多于是就到其官网下载了2.1.9版本的jotm进过实际测试发现其基本能够满足分布式事务提交及异常回滚的基本需求,但在测试中发现三个问题:
1. 发现spring3已经不支持jotm了,在其org.springframework.transaction-3.1.2.RELEASE.jar包中已将org.springframework.transaction.jta.JotmFactoryBean.class移除,只能将spring2.x中的JotmFactoryBean放入spring3.x对应的包路径内;
2. 启动后发现jotm启动的某些线程不能自动关闭,网上关于此次资料太少未能解决;
3. 在将lo4j日志级别调成debug时,启动会报错java.lang.ClassNotFoundException:org.ow2.cmi.controller.factory.ClusterViewManagerFactoryConfig这个错误百度之后发现查找结果为空,虽说不影响正常使用但是心里还是不太舒服;
基于以上三个原因最终在项目中还是放弃了使用jotm;
然后又在网上查找其他开源jta实现,最终锁定了atomikos,因为不知道怎么读我还是习惯叫它aotm,据说它原来是商用收费的才刚刚开源所有还是比较靠谱的。
首先登陆其官网http://www.atomikos.com/但要注意的是,要下载aotm必须进行在线注册然后它会把下载地址发送的你的邮箱里,我下载的是3.8.0版本的aotm,参见examples再结合之前查找的资料很顺利的完成了分布式事务提交及回滚测试,下面将部分关键配置帖出以供参考:
1. 添加工程依赖包:
atomikos-util.jar
transactions.jar
transactions-api.jar
transactions-jdbc.jar
transactions-jta.jar
jta.jar (需要单独另下载)
2. 在工程classse目录下将下载的aotm中的jta.properties文件放入其中(打开此文件会发现很多配置项,不过幸好都有默认值基本不改就能用,如果项目需要可参见官网上的说明)
3. 打开spring的配置文件在其中加
<!-- 配置数据源(资源管理器) -->
<bean id="dataSourceA" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<description>mysql xa datasource</description>
<property name="uniqueResourceName"><value>dataSourceA</value></property>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="URL">jdbc:mysql://localhost/usera</prop>
</props>
</property>
<!-- 连接池里面连接的个数? -->
<property name="poolSize" value="3"/>
</bean>
<bean id="dataSourceB" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<description>mysql xa datasource</description>
<property name="uniqueResourceName"><value>dataSourceB</value></property>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="URL">jdbc:mysql://localhost/userb</prop>
</props>
</property>
<!-- 连接池里面连接的个数? -->
<property name="poolSize" value="3"/>
</bean>
<!-- 配置Transcation(事务管理器)-->
<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>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout"><value>300</value></property>
</bean>
<bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager"><ref bean="atomikosTransactionManager" /></property>
<property name="userTransaction"><ref bean="atomikosUserTransaction" /></property>
</bean>
(注意:如果使用oracle数据库需以SYSDBA登录SQL Plus给数据库用户赋予三项查询事务相关权限及一项执行系统函数权限,如果赋予在启动时回报Error in recovery异常;
grant select on sys.dba_pending_transactions to 当前数据库用户;
grant select on sys.pending_trans$ to 当前数据库用户;
grant select on sys.dba_2pc_pending to 当前数据库用户;
grant execute on sys.dbms_system to 当前数据库用户;
)
分布式事务必须由支持XA协议的资源管理器(数据源)及支持JTA的事务管理器(TranscationManager)两部分构成其余跟非分布式事务程序配置无异;
作者注明:
通过此次在项目中加入分布式事务支持有如下所感:
1.网上有很多不负责任的人乱贴代码一个错误的demo会被无数人转载,其结果只能是错上加错;
2.做一件事没有捷径可走,最好的方法是先了解清楚你要用的技术究竟是怎么回事,否则只看demo就算能调通今后也很容易出现这样或那样的问题;
3.看了不少人写的demo虽然写的很全很详细却混入了很多非关键的运行代码这对阅读及代码迁移带来了很多不便。