内容简介:Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器,主要用于处理跨数据库事务,比如某个指令在A库和B库都有写操作,业务上要求A库和B库的写操作要具有原子性,这时候就可以用到atomikos。笔者这里整合了一个spring和atomikos的demo,并且通过案例演示说明atomikos的作用。开发工具:idea数据库:mysql , oracle
前言
Atomikos 是一个为 Java 平台提供增值服务的并且开源类事务管理器,主要用于处理跨数据库事务,比如某个指令在A库和B库都有写操作,业务上要求A库和B库的写操作要具有原子性,这时候就可以用到atomikos。笔者这里整合了一个spring和atomikos的demo,并且通过案例演示说明atomikos的作用。
准备工作
开发工具:idea
数据库:mysql , oracle
正文
源码地址: github.com/qw870602/at…
演示原理:通过在两个库的写操作之间人为制造异常来观察数据库是否回滚
演示步骤:1.正常写操作,观察数据库值的变化情况
2.在写操作语句之间制造异常,观察数据库值的变化情况
项目结构
从web.xml中可以知道,容器只加载了appliactionContext.xml,剩下的配置文件除了database.properties外都是无用文件,所以大家如果要在项目中配置的话,仅需要把appliactionContext.xml中关于atomikos的部分新增到自己项目中就OK了
appliactionContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 引入数据源信息的properties属性文件 -->
<context:property-placeholder location="classpath:database.properties" />
<!-- XA方式 -->
<!-- MYSQL数据库配置 -->
<bean id="mysqlDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
<property name="uniqueResourceName" value="dataSource1"/>
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="xaProperties">
<props>
<prop key="URL">${mysql.qa.db.url}</prop>
<prop key="user">${mysql.qa.db.user}</prop>
<prop key="password">${mysql.qa.db.password}</prop>
</props>
</property>
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="borrowConnectionTimeout" value="30" />
<property name="maintenanceInterval" value="60" />
</bean>
<!-- ORACLE数据库配置 -->
<bean id="oracleDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
<property name="uniqueResourceName" value="dataSource2"/>
<property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${oracle.qa.db.url}</prop>
<prop key="user">${oracle.qa.db.user}</prop>
<prop key="password">${oracle.qa.db.password}</prop>
</props>
</property>
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="borrowConnectionTimeout" value="30" />
<property name="maintenanceInterval" value="60" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--<property name="configLocation" value="classpath:mybatis-config-mysql.xml" />-->
<property name="dataSource" ref="mysqlDataSource" />
<property name="mapperLocations" >
<list>
<value>classpath*:/dao/*.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionFactoryOracle" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--<property name="configLocation" value="classpath:mybatis-config.xml" />-->
<property name="dataSource" ref="oracleDataSource" />
<property name="mapperLocations" >
<list>
<value>classpath*:/daodev/*.xml</value>
</list>
</property>
</bean>
<!-- MyBatis为不同的mapper注入sqlSessionFactory -->
<bean id="mysqlTransactionTestDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="mapperInterface" value="com.xy.dao.MysqlTransactionTestDao" />
</bean>
<bean id="transactionTestDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactoryOracle" />
<property name="mapperInterface" value="com.xy.dao.TransactionTestDao" />
</bean>
<!-- 分布式事务 -->
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown" value="true"/>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300"/>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager"/>
<property name="userTransaction" ref="atomikosUserTransaction"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:annotation-config/>
<!--<!– 自动扫描controller包下的所有类,如果@Controller注入为bean –>-->
<!--<!–事务管理层–>-->
<context:component-scan base-package="com.xy" />
<!-- 注册拦截器 -->
<!--<mvc:interceptors>
<bean class="com.springmybatis.system.interceptor.MyInterceptor" />
</mvc:interceptors>-->
</beans>复制代码
适用JUnit4进行单元测试
package com.xy.controller;
import com.xy.daodev.TransactionTestService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TransactionTestMain extends AbstractJUnit4SpringContextTests {
@Autowired
private TransactionTestService transactionTestService;
/**
* 在同一事务有多个数据源
*/
@Test
public void multipleDataSource2() {
transactionTestService.updateMultipleDataSource("1","1", 100L,"1.6");
}
}复制代码
业务实现,当前没有异常操作
@Service
public class TransactionTestServiceImpl implements TransactionTestService {
@Autowired
@Qualifier("mysqlTransactionTestDao")
private MysqlTransactionTestDao mysqlTransactionTestDao;
@Autowired
@Qualifier("transactionTestDao")
private TransactionTestDao transactionTestDao;
/**
* 在同一事务有多个数据源
*/
@Override
@Transactional
public void updateMultipleDataSource(String deUserId, String inUserid, long money,String str) {
// 账户1转出操作
mysqlTransactionTestDao.decreaseMoney(deUserId, money);
//Integer.parseInt(str);
// 账户2转入操作
transactionTestDao.increaseMoney(inUserid, money);
}
}复制代码
mysql模拟金额转出,oracle模拟金额转入
<update id="decreaseMoney" parameterType="java.util.Map">
UPDATE fx1 SET amount=amount - #{1,jdbcType=BIGINT} WHERE id=#{0,jdbcType=VARCHAR}
</update>复制代码
<update id="increaseMoney">
UPDATE fx1 SET amount=amount + #{1,jdbcType=BIGINT} WHERE id=#{0,jdbcType=VARCHAR}
</update>
复制代码
mysql初始金额
oracle初始金额
执行正常操作
mysql当前金额
oracle当前金额
将被屏蔽的制造异常的代码打开
public void updateMultipleDataSource(String deUserId, String inUserid, long money,String str) {
// 账户1转出操作
mysqlTransactionTestDao.decreaseMoney(deUserId, money);
Integer.parseInt("skg");
// 账户2转入操作
transactionTestDao.increaseMoney(inUserid, money);
} 复制代码
发现 mysql 和oracle的当前金额都没有变化,说明事务回滚成功,查看日志
发现控制台打印出了异常信息,并且atomikos调用了rollback()方法,从日志也证实了回滚成功。
以上所述就是小编给大家介绍的《spring整合atomikos实现分布式事务》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- SpringBoot开发案例之整合Dubbo分布式服务
- SpringBoot开发案例之整合Dubbo分布式服务
- 5分钟实现SpringBoot整合Dubbo构建分布式服务
- Spring Boot 2 整合 FastDFS 中间件,实现文件分布式管理
- 【Springboot】实例讲解Springboot整合OpenTracing分布式链路追踪系统(Jaeger和Zipkin)
- SpringBoot整合MybatisPlus的简单教程(简单整合)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
海量运维、运营规划之道
唐文 / 电子工业出版社 / 2014-1-1 / 59.00
《海量运维、运营规划之道》作者具有腾讯、百度等中国一线互联网公司多年从业经历,书中依托工作实践,以互联网海量产品质量、效率、成本为核心,从规划、速度、监控、告警、安全、管理、流程、预案、考核、设备、带宽等方面,结合大量案例与读者分享了作者对互联网海量运维、运营规划的体会。 《海量运维、运营规划之道》全面介绍大型互联网公司运维工作所涉及的各个方面,是每个互联网运维工程师、架构师、管理人员不可或......一起来看看 《海量运维、运营规划之道》 这本书的介绍吧!
XML、JSON 在线转换
在线XML、JSON转换工具
正则表达式在线测试
正则表达式在线测试