分布式事务atomikos

       上一篇介绍了分库分表插件,但是多库操作涉及到分布式事务问题,大家都知道分布式事务需要涉及到数据库XA驱动,oracle原本就支持,mysql在5.6版本支持了该属性,atomikos插件封装了该特性的一个中间件。现在来介绍一个atomikos的使用。

       首先是jar包依赖,maven配置如下:

<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions</artifactId>
	<version>4.0.4</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-api</artifactId>
	<version>4.0.4</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>atomikos-util</artifactId>
	<version>4.0.4</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-jdbc-deprecated</artifactId>
	<version>3.8.0</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-jta</artifactId>
	<version>4.0.4</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-jdbc</artifactId>
	<version>4.0.4</version>
</dependency>

      额外的还要增加jta的配置,使用jta管理spring事务:

<dependency>
	<groupId>javax.transaction</groupId>
	<artifactId>jta</artifactId>
	<version>1.1</version>
</dependency>

 然后是srping配置,由于需要使用atomikos数据源,所以对上一篇分库分表插件的数据源配置做了修改:

<?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:rdb="http://www.dangdang.com/schema/ddframe/rdb"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
			http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	        http://www.dangdang.com/schema/ddframe/rdb
		    http://www.dangdang.com/schema/ddframe/rdb/rdb.xsd"
            >

	<!-- 配置数据源 -->
	<bean name="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
		<!--		<property name="driverClassName" value="${jdbc.driverClassName}" /> -->
		<property name="uniqueResourceName" value="dataSource" />
		<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
		<property name="xaProperties">
			<props>
				<prop key="user">${jdbc.username}</prop>
				<prop key="password">${jdbc.password}</prop>
				<prop key="url">${jdbc.url}</prop>
			</props>
		</property>
		<property name="minPoolSize" value="5" />
		<property name="maxPoolSize" value="50" />
		<property name="maxIdleTime" value="60" />
	</bean>

	<!-- 配置数据源 -->
	<bean name="master0" class="com.atomikos.jdbc.AtomikosDataSourceBean"  destroy-method="close">
		<!--		<property name="driverClassName" value="${jdbc.driverClassName}" /> -->
		<property name="uniqueResourceName" value="master0" />
		<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
		<property name="xaProperties">
			<props>
				<prop key="user">${jdbc.username}</prop>
				<prop key="password">${jdbc.password}</prop>
				<prop key="url">jdbc:mysql://127.0.0.1:3306/demodb00</prop>
			</props>
		</property>
		<property name="minPoolSize" value="5" />
		<property name="maxPoolSize" value="50" />
		<property name="maxIdleTime" value="60" />
	</bean>

	<!-- 配置数据源 -->
	<bean name="master1" class="com.atomikos.jdbc.AtomikosDataSourceBean"  destroy-method="close">
		<!--		<property name="driverClassName" value="${jdbc.driverClassName}" /> -->
		<property name="uniqueResourceName" value="master1" />
		<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
		<property name="xaProperties">
			<props>
				<prop key="user">${jdbc.username}</prop>
				<prop key="password">${jdbc.password}</prop>
				<prop key="url">jdbc:mysql://127.0.0.1:3306/demodb01</prop>
			</props>
		</property>
		<property name="minPoolSize" value="5" />
		<property name="maxPoolSize" value="50" />
		<property name="maxIdleTime" value="60" />
	</bean>

	<rdb:strategy id="idDbSharding" sharding-columns="id"
				  algorithm-class="com.feng.splitdbtb.DbAlgorithm"/>

	<rdb:strategy id="idTbSharding" sharding-columns="id"
				  algorithm-class="com.feng.splitdbtb.TbAlgorithm"/>

	<rdb:data-source id="wholeDataSource">
		<rdb:sharding-rule data-sources="master0,master1">
			<rdb:table-rules>
				<rdb:table-rule logic-table="user" actual-tables="user_${0..1}"
								database-strategy="idDbSharding" table-strategy="idTbSharding"/>
			</rdb:table-rules>
		</rdb:sharding-rule>
	</rdb:data-source>

	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="wholeDataSource" />
		<property name="configLocation" value="classpath:mybatis-config.xml"/>
		<property name="mapperLocations"  >
			<list>
				<value>classpath:com/feng/mapper/user/*.xml</value>
			</list>
		</property>
	</bean>

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.feng.dao.user" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>

	<!-- 定义事务 -->
	<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
		  init-method="init" destroy-method="close">
		<property name="forceShutdown">
			<value>true</value>
		</property>
	</bean>

	<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
		<property name="transactionTimeout" value="300" />
	</bean>

	<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>
	<tx:advice id="txAdvice" transaction-manager="springTransactionManager">
		<tx:attributes>
			<tx:method name="publish*" />
			<tx:method name="save*" />
			<tx:method name="add*" />
			<tx:method name="update*" />
			<tx:method name="insert*" />
			<tx:method name="create*" />
			<tx:method name="del*" />
			<tx:method name="load*" />
			<tx:method name="init*" />

			<tx:method name="*"  read-only="true"/>
		</tx:attributes>
	</tx:advice>
 	<!-- AOP配置-->
	<aop:config>
		<aop:pointcut id="myPointcut"
			expression="execution(public * com.feng.service.impl.*.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
	</aop:config>

	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
	</bean>
</beans>

       运行一下,看到以下日志的兄弟,说明已经成功了,内心一阵狂热,胸膛也挺直了。    

[DEBUG][2017-04-17 09:58:27,821][com.atomikos.icatch.imp.CompositeTransactionImp]addParticipant ( XAResourceTransaction: 636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D313439323339343330373730353030303035:636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D35 ) for transaction com.atomikos.spring.jdbc.tm149239430770500005
[DEBUG][2017-04-17 09:58:27,821][com.atomikos.datasource.xa.XAResourceTransaction]XAResource.start ( 636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D313439323339343330373730353030303035:636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D35 , XAResource.TMNOFLAGS ) on resource master1 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@2c7e446d
[DEBUG][2017-04-17 09:58:27,840][com.atomikos.icatch.imp.CompositeTransactionImp]registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@1f21ef16 ) for transaction com.atomikos.spring.jdbc.tm149239430770500005
[DEBUG][2017-04-17 09:58:27,841][com.atomikos.jdbc.AtomikosConnectionProxy]atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@2015fa5c: calling prepareStatement(INSERT INTO user_1 (id, name, age) VALUES (?, ?, ?),1003,1007,1)...
[DEBUG][2017-04-17 09:58:27,866][org.mybatis.spring.SqlSessionUtils]Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ac88402]
[DEBUG][2017-04-17 09:58:27,866][org.mybatis.spring.SqlSessionUtils]Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ac88402]
[DEBUG][2017-04-17 09:58:27,866][org.mybatis.spring.SqlSessionUtils]Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ac88402]
[DEBUG][2017-04-17 09:58:27,866][org.springframework.jdbc.datasource.DataSourceUtils]Returning JDBC Connection to DataSource
[DEBUG][2017-04-17 09:58:27,866][com.atomikos.jdbc.AtomikosConnectionProxy]atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@2015fa5c: close()...
[DEBUG][2017-04-17 09:58:27,866][com.atomikos.datasource.xa.XAResourceTransaction]XAResource.end ( 636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D313439323339343330373730353030303035:636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D35 , XAResource.TMSUCCESS ) on resource master1 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@2c7e446d
[DEBUG][2017-04-17 09:58:27,885][org.springframework.transaction.jta.JtaTransactionManager]Initiating transaction rollback
[DEBUG][2017-04-17 09:58:27,887][com.atomikos.datasource.xa.XAResourceTransaction]XAResource.rollback ( 636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D313439323339343330373730353030303035:636F6D2E61746F6D696B6F732E737072696E672E6A6462632E746D35 ) on resource master1 represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4MysqlXAConnection@2c7e446d
[DEBUG][2017-04-17 09:58:27,906][com.atomikos.icatch.imp.CompositeTransactionImp]rollback() done of transaction com.atomikos.spring.jdbc.tm149239430770500005
[DEBUG][2017-04-17 09:58:27,907][com.atomikos.icatch.imp.CompositeTransactionImp]rollback() done of transaction com.atomikos.spring.jdbc.tm149239430770500005

   

最后提醒一下,业务的相关方法一定不要捕获异常,抛出来RunTimeException也不行,否则atomikos不能回滚,具体原因不明。

猜你喜欢

转载自songfeng-123.iteye.com/blog/2369508