SpringMvc + Mybatis项目中 使用 Atomikos实现分布式事务

背景:项目架构使用了SpringMvc + Mybatis,同时在使用多数据源的时候需要满足事务一致性

  通俗的说法是:项目中配置了多个数据源,并且在一个service方法中使用多个数据源的时候需要保证事务一致性。

  网上的主流资料大概讲解了两种spring对分布式事务的实现:jotm和Atomikos,需要注意的是使用jotm的时候需要用到一个类org.springframework.transaction.jta.JotmFactoryBean然而在spring 3.x之后移除了这个类,所以我采用了Atomikos的方式。

  实现过程如下:

  1、在使用了Atomikos之后需要注意DataSource不能再使用c3p0 之类的驱动了,需要用到com.atomikos.jdbc.AtomikosDataSourceBean,下面是两个DataSource的配置示例:

  

 1 <bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
 2         <property name="uniqueResourceName" value="XA1DBMS1" />  
 3         <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />  
 4         <property name="xaProperties">  
 5             <props>  
 6                 <prop key="URL">${dataPortal_mysql_jdbc_url}</prop>  
 7                 <prop key="user">${dataPortal_mysql_jdbc_user}</prop>  
 8                 <prop key="password">${dataPortal_mysql_jdbc_password}</prop>  
 9             </props>  
10         </property>  
11         <property name="poolSize" value="3" />  
12         <property name="minPoolSize" value="3" />  
13         <property name="maxPoolSize" value="5" />
14     </bean>
15     
16     <bean id="webDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
17         <property name="uniqueResourceName" value="XA1DBMS2" />  
18         <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />  
19         <property name="xaProperties">  
20             <props>  
21                 <prop key="URL">${web.jdbc.url}</prop>  
22                 <prop key="user">${web.jdbc.username}</prop>  
23                 <prop key="password">${web.jdbc.password}</prop>  
24             </props>  
25         </property>  
26         <property name="poolSize" value="3" />  
27         <property name="minPoolSize" value="3" />  
28         <property name="maxPoolSize" value="5" />
29     </bean>

 这里一些其他的参数,比如最大连接数,超时时间的参数我是在com.atomikos.jdbc.AtomikosDataSourceBean源码中找到的:

 

两个DataSource中webDataSource我采用的是spring的JdbcTemplate去写sql而dataSource则配置使用了mybatis的方式

2、两种不同的方式配置如下:

 1 <!-- web库jdbcTemplate -->
 2     <bean id="webJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
 3         <property name="dataSource" ref="webDataSource" />
 4     </bean>
 5     <!-- gmt库jdbcTemplate -->
 6     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
 7         <property name="dataSource">
 8             <ref bean="dataSource" />
 9         </property>
10     </bean>
11     
12     <!-- 创建SqlSessionFactory,同时指定数据源 -->
13     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
14         <property name="dataSource" ref="dataSource" />
15         <property name="mapperLocations"  value="classpath:com/sincetimes/modernship/**/dao/*.xml"/>
16     </bean>
17     
18     <!-- mybatis自动扫描器 -->
19     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
20         <property name="basePackage" value="com.sincetimes.modernship.dao" />
21         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
22     </bean>
23     
24     <!-- DAO使用mybatis进行数据库访问操作 -->
25     <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
26         <constructor-arg index="0" ref="sqlSessionFactory" />
27     </bean>

3、在配置事务的时候,我们可以使用@Transactional注解,也可以写aop

 1 <!-- 分布式事务 -->
 2     <bean id="userTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">  
 3         <property name="transactionTimeout" value="300" />  
 4     </bean>  
 5 
 6     <bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
 7         <property name="userTransaction" ref="userTransaction" />   
 8     </bean>
 9 
10     <tx:annotation-driven transaction-manager="springTransactionManager"/>
11 
12     <aop:config>
13         <aop:pointcut id="baseServiceMethods" expression="execution(* com.sincetimes..impl..*.*(..))" />
14         <aop:advisor pointcut-ref="baseServiceMethods" advice-ref="txAdvice"/>
15     </aop:config>
16 
17     <!-- 配置事务的传播特性 -->
18     <tx:advice id="txAdvice" transaction-manager="springTransactionManager">
19         <tx:attributes>
20             <tx:method name="query*" propagation="REQUIRED" read-only="true" />
21             <tx:method name="get*" propagation="REQUIRED" read-only="true" />
22             <tx:method name="find*" propagation="REQUIRED" read-only="true" />
23             <tx:method name="list*" propagation="REQUIRED" read-only="true" />
24             <tx:method name="count*" propagation="REQUIRED" read-only="true" />
25             <tx:method name="insert*" propagation="REQUIRED" />
26             <tx:method name="add*" propagation="REQUIRED" />
27             <tx:method name="del*" propagation="REQUIRED" />
28             <tx:method name="save*" propagation="REQUIRED" />
29             <tx:method name="update*" propagation="REQUIRED" />
30             <tx:method name="edit*" propagation="REQUIRED" />
31             <tx:method name="enable*" propagation="REQUIRED" />                
32             <tx:method name="upload*" propagation="REQUIRED" />                
33         </tx:attributes>
34     </tx:advice>

分布式事务中的重点是事务管理器。在Atomikos中对应的就是 com.atomikos.icatch.jta.UserTransactionManager 

4、如果项目使用了log4j的话,并且日志级别为info,在项目启动后会发现有很多atomikos的info日志打印出来,这个时候在log4j的配置文件中增加一个配置:log4j.logger.com.atomikos = error 即可。

这里参考了网上找到的资料:https://my.oschina.net/pingpangkuangmo/blog/413518

 

posted on 2017-11-01 17:53  FlyHeLanMan  阅读(8017)  评论(0编辑  收藏  举报

导航