声明:本片文章来源于开源社区论坛转载~!奋斗
使用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一样卖服务支持的。而且论坛页比较活跃,有问题很快可以解决。