前言

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/>
<!--&lt;!&ndash; 自动扫描controller包下的所有类,如果@Controller注入为bean &ndash;&gt;-->
<!--&lt;!&ndash;事务管理层&ndash;&gt;-->
<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实现分布式事务的更多相关文章

  1. 事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理

    1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...

  2. Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现分布式事务管理

    原创说明:本文为本人原创作品,绝非他处转载,转账请注明出处 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). ...

  3. Spring+JTA+Atomikos+mybatis分布式事务管理

    我们平时的工作中用到的Spring事务管理是管理一个数据源的.但是如果对多个数据源进行事务管理该怎么办呢?我们可以用JTA和Atomikos结合Spring来实现一个分布式事务管理的功能.了解JTA可 ...

  4. 分布式事务、多数据源、分库分表中间件之spring boot基于Atomikos+XADataSource分布式事务配置(100%纯动态)

    本文描述spring boot基于Atomikos+DruidXADataSource分布式事务配置(100%纯动态),也就是增加.减少数据源只需要修改application.properties文件 ...

  5. Spring+iBatis+Atomikos实现JTA事务

    Atomikos是一个公司名字,旗下最著名的莫过于其Atomikos的事务管理器产品. 产品分两个:一个是开源的TransactionEssentials,一个是商业的ExtremeTransacti ...

  6. spring+mybatis+atomikos 实现JTA事务

    1. 选择哪种transaction manager?      在单数据源情况下,JDBC,Hibernate,ibatis等自带的 transaction manager已能用于处理事务.     ...

  7. Spring Cloud异步场景分布式事务怎样做?试试RocketMQ

    一.背景 在微服务架构中,我们常常使用异步化的手段来提升系统的 吞吐量 和 解耦 上下游,而构建异步架构最常用的手段就是使用 消息队列(MQ),那异步架构怎样才能实现数据一致性呢?本文主要介绍如何使用 ...

  8. JTA集成JOTM或Atomikos配置分布式事务(Tomcat应用服务器)

    一.以下介绍Spring中直接集成JOTM提供JTA事务管理.将JOTM集成到Tomcat中. (经过测试JOTM在批量持久化时有BUG需要修改源码GenericPool类解决)! 参考文章http: ...

  9. DTP模型之二:(XA协议之二)JTA集成JOTM或Atomikos配置分布式事务(Tomcat应用服务器)

    jotm只能用的xapool数据源,而且很少更新. 一.以下介绍Spring中直接集成JOTM提供JTA事务管理.将JOTM集成到Tomcat中. (经过测试JOTM在批量持久化时有BUG需要修改源码 ...

随机推荐

  1. 第八届蓝桥杯C/C++程序设计本科B组决赛 ——瓷砖样式(填空题)【DP?我的暴力排列搜索】

    标题:磁砖样式 小明家的一面装饰墙原来是 3*10 的小方格. 现在手头有一批刚好能盖住2个小方格的长方形瓷砖. 瓷砖只有两种颜色:黄色和橙色. 小明想知道,对于这么简陋的原料,可以贴出多少种不同的花 ...

  2. How to parse unix timestamp to time.Time

      The time.Parse function does not do Unix timestamps. Instead you can use strconv.ParseInt to parse ...

  3. Java下的tinylog日志打印

    做个笔记. 做某个功能时需要DEBUG调试日志,但是直接System.out.println 是打印在终端,有些情况下是看不到输出的,所以需要用日志框架去打印输出值. 经过搜索完以后发现Logback ...

  4. 面试官:讲讲mysql表设计要注意啥

    内容时参考一个博主的,内容写的很好,就忍不住拿过来了,如遇到,请见谅 参考连接:https://www.cnblogs.com/rjzheng/p/11174714.html

  5. 编写一个求圆面积的C语言程序

    #include<stdio.h>   //文件包含//#define PI 3.14     //宏定义//void main()         { float r,s; scanf( ...

  6. div 水平垂直居中

    css <style> .main{ background: #999999; width: 600px; height: 400px; position: absolute; top: ...

  7. LeetCode 246. Strobogrammatic Number

    原题链接在这里:https://leetcode.com/problems/strobogrammatic-number/ 题目: A strobogrammatic number is a numb ...

  8. 去除IDEA中xml黄色背景

    idea版本:IntelliJ IDEA 2019.2.1 在编写mybatis的xml中会出现大面积黄色背景提示,看起来比较不舒服. 去掉黄色背景颜色 1.打开File->Settings-& ...

  9. learning scala view collection

    The view method will create a non-strict version of the collection which means that the elements of ...

  10. Linux操作系统常用命令合集——第六篇-软件包操作(2个命令)

    一.前言介绍 软件包即程序包 程序包管理 关键词:rpm程序包管理.YUM仓库管理.源码编译安装 程序包管理: 将编译好的应用程序的各组成文件打包一个或几个程序包文件,从而方便快捷地实现程序包的安装. ...