spring整合atomikos实现分布式事务
前言
Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器,主要用于处理跨数据库事务,比如某个指令在A库和B库都有写操作,业务上要求A库和B库的写操作要具有原子性,这时候就可以用到atomikos。笔者这里整合了一个spring和atomikos的demo,并且通过案例演示说明atomikos的作用。
准备工作
开发工具:idea
数据库:mysql , oracle
正文
演示原理:通过在两个库的写操作之间人为制造异常来观察数据库是否回滚
演示步骤 :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()方法,从日志也证实了回滚成功。
END
作者:胖子k
链接:https://juejin.im/post/5ce24d4ce51d45109b01b0f4
spring整合atomikos实现分布式事务的更多相关文章
- 事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理
1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...
- Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现分布式事务管理
原创说明:本文为本人原创作品,绝非他处转载,转账请注明出处 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). ...
- Spring+JTA+Atomikos+mybatis分布式事务管理
我们平时的工作中用到的Spring事务管理是管理一个数据源的.但是如果对多个数据源进行事务管理该怎么办呢?我们可以用JTA和Atomikos结合Spring来实现一个分布式事务管理的功能.了解JTA可 ...
- 分布式事务、多数据源、分库分表中间件之spring boot基于Atomikos+XADataSource分布式事务配置(100%纯动态)
本文描述spring boot基于Atomikos+DruidXADataSource分布式事务配置(100%纯动态),也就是增加.减少数据源只需要修改application.properties文件 ...
- Spring+iBatis+Atomikos实现JTA事务
Atomikos是一个公司名字,旗下最著名的莫过于其Atomikos的事务管理器产品. 产品分两个:一个是开源的TransactionEssentials,一个是商业的ExtremeTransacti ...
- spring+mybatis+atomikos 实现JTA事务
1. 选择哪种transaction manager? 在单数据源情况下,JDBC,Hibernate,ibatis等自带的 transaction manager已能用于处理事务. ...
- Spring Cloud异步场景分布式事务怎样做?试试RocketMQ
一.背景 在微服务架构中,我们常常使用异步化的手段来提升系统的 吞吐量 和 解耦 上下游,而构建异步架构最常用的手段就是使用 消息队列(MQ),那异步架构怎样才能实现数据一致性呢?本文主要介绍如何使用 ...
- JTA集成JOTM或Atomikos配置分布式事务(Tomcat应用服务器)
一.以下介绍Spring中直接集成JOTM提供JTA事务管理.将JOTM集成到Tomcat中. (经过测试JOTM在批量持久化时有BUG需要修改源码GenericPool类解决)! 参考文章http: ...
- DTP模型之二:(XA协议之二)JTA集成JOTM或Atomikos配置分布式事务(Tomcat应用服务器)
jotm只能用的xapool数据源,而且很少更新. 一.以下介绍Spring中直接集成JOTM提供JTA事务管理.将JOTM集成到Tomcat中. (经过测试JOTM在批量持久化时有BUG需要修改源码 ...
随机推荐
- Codeforces #366 Div. 2 C. Thor (模拟
http://codeforces.com/contest/705/problem/C 题目 模拟题 : 设的方法采用一个 r 数组(第几个app已经阅读过的消息的数量),和app数组(第几个app发 ...
- JVM堆空间用途分析与划分依据
在上一次[https://www.cnblogs.com/webor2006/p/9876493.html]已经对JVM的内存空间的划分进行了理论化的学习,这次还是对上一次提到的理论进行进一步的补充, ...
- JDBC课程1-实现Driver接口连接mysql数据库、通用的数据库连接方法(使用文件jdbc.properties)
package day_18; import jdk.internal.util.xml.impl.Input; import org.junit.Test; import java.io.Input ...
- MySQL进阶14--标识列(自增序列/auto_increment)--设置/展示步长--设置/删除标示列
/*进阶14 标识列 又称为自增序列; 含义 : 可以不用手动的插入值, 系统提供默认的序列值(1-->n) 特点 : 1.标识列必须和主键搭配? 不一定,但要求是一个key 2.一个表可以有几 ...
- flask中使用ajax 处理前端请求,结果展示在同一页面,不点击页面不展示
在同一页面点击按钮,后端处理后展示在同一页面,不点击隐藏该结果:与上一篇大同小异,需要在 html.flask.js微调 效果展示: (未点击查询) (点击查询) html: <html> ...
- myeclipse2018修改主题
- 通过自定义属性获取指定checkbox是否选中
$("input[conferid='"+conferid+"']").is(':checked'); $("input[conferid='1234 ...
- How to Fix a Frozen Mac When Updating macOS
How to Fix a Frozen Mac When Updating macOS By Mike Tee – Posted on Sep 1, 2019 in Mac While macOS ...
- ES 的基本用法
ES的基本用法 ES的基本概念 1> 集群和节点 一个es集群是由一个或多和es节点组成的集合 每一个集群都有一个名字, 如之前的wali 每个节点都有自己的名字, 如之前的master, sl ...
- Jquery使用心得
1.<form>提交时,会提交里面有name属性的元素,而不是id属性 $("#form").serialize(); 得到里面每个元素的拼接值 id=1& ...