我们平时的工作中用到的Spring事务管理是管理一个数据源的。但是如果对多个数据源进行事务管理该怎么办呢?我们可以用JTA和Atomikos结合Spring来实现一个分布式事务管理的功能。了解JTA可以看一下这篇文章。下面我们看怎么实现分布式事务的。
步骤一:添加pom.xml依赖
步骤二:准备配置文件。jdbc.properties,jta.properties
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.one.url=jdbc:mysql://127.0.0.1:3306/zsyy-pt-ls?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull jdbc.one.username=root jdbc.one.password=esbmysql@ucmed.com jdbc.two.url=jdbc:mysql://127.0.0.1:3306/zsyy-pt-test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull jdbc.two.username=root jdbc.two.password=esbmysql@ucmed.com
jta.properties
com.atomikos.icatch.registered=true
com.atomikos.icatch.console_file_name=ls2rm.out
com.atomikos.icatch.log_base_name=base_log
com.atomikos.icatch.log_base_dir=lslog
步骤三、配置两个数据源
<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close" abstract="true"> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/> <property name="poolSize" value="10"/> <property name="minPoolSize" value="10"/> <property name="maxPoolSize" value="30"/> <property name="borrowConnectionTimeout" value="60"/> <property name="reapTimeout" value="20"/> <property name="maxIdleTime" value="60"/> <property name="maintenanceInterval" value="60"/> <property name="testQuery"> <value>SELECT 1</value> </property> </bean> <!-- 配置数据源一 --> <bean id="dataSourceOne" parent="abstractXADataSource"> <property name="uniqueResourceName"> <value>dataSourceOne</value> </property> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/> <property name="xaProperties"> <props> <prop key="URL">${jdbc.one.url}</prop> <prop key="user">${jdbc.one.username}</prop> <prop key="password">${jdbc.one.password}</prop> </props> </property> </bean> <!--配置数据源二--> <bean id="dataSourceTwo" parent="abstractXADataSource"> <property name="uniqueResourceName"> <value>dataSourceTwo</value> </property> <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" /> <property name="xaProperties"> <props> <prop key="URL">${jdbc.two.url}</prop> <prop key="user">${jdbc.two.username}</prop> <prop key="password">${jdbc.two.password}</prop> <prop key="pinGlobalTxToPhysicalConnection">true</prop> </props> </property> </bean>
步骤四、配置分布式事务
<!--配置分布式事务--> <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close"> <property name="forceShutdown" value="false"/> </bean> <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"> <property name="transactionTimeout" value="300000"/> </bean> <!--JTA事务管理器--> <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager"> <ref bean="atomikosTransactionManager"/> </property> <property name="userTransaction"> <ref bean="atomikosUserTransaction"/> </property> <property name="allowCustomIsolationLevels" value="true"/> </bean> <aop:aspectj-autoproxy /> <!--声明式事务--> <aop:config proxy-target-class="true"> <aop:advisor advice-ref="txAdvice" pointcut="execution(* org.hope.database.one.service.MemberServiceImpl.addMemberAndPoints(..))"/> </aop:config> <tx:advice id="txAdvice" transaction-manager="springTransactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" read-only="true"/> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/> </tx:attributes> </tx:advice>
步骤五、配置mybatis
<!--mybatis的相关配置--> <bean id="sqlSessionFactoryOne" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSourceOne"/> <property name="configLocation" value="mybatis-config.xml"/> <property name="typeAliasesPackage" value="org.hope.database.one.model"/> <property name="mapperLocations"> <list> <value>classpath:mapper/one/*.xml</value> </list> </property> </bean> <bean id="sqlSessionFactoryTwo" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSourceTwo"/> <property name="configLocation" value="mybatis-config.xml"/> <property name="typeAliasesPackage" value="org.hope.database.two.model"/> <property name="mapperLocations"> <list> <value>classpath:mapper/two/*.xml</value> </list> </property> </bean> <!--配置mybatis映射文件自动扫描--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="org.hope.database.one"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryOne"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="org.hope.database.two"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryTwo"/> </bean>
步骤六、写对应的service
dao和model这个直接看代码吧。
package org.hope.database.one.service; import org.hope.database.one.dao.MemberMapper; import org.hope.database.two.dao.PointMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("memberServiceWa") public class MemberServiceImpl implements MemberService { @Autowired private MemberMapper memberMapper; @Autowired private PointMapper pointMapper; public void addMemberAndPoints(String name, int point) { memberMapper.addMember(name); String str = null; str.equals("wge");//此处会出现异常 pointMapper.addPoint(point); } }
步骤七、单元测试
package org.hope.service; import org.hope.database.one.service.MemberService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath*:applicationContext.xml"}) public class MemberServiceTest { @Autowired private MemberService memberServiceWa; @Test public void addMemberAndPointTest() { String name = "马化腾"; int points = 50; memberServiceWa.addMemberAndPoints(name, points); } }
https://gitee.com/huayicompany/spring-learn/tree/master/srping-jta-atomikos
参考:
[1] 博客,http://blog.csdn.net/zeroctu/article/details/53116351
[2] 博客,http://blog.csdn.net/sun8288/article/details/8674016,Atomickos中文文档