spring分布式事务控制
应用场景
问题描述
解决方法
多数据源配置
单元测试
第一种方法:最大努力一次提交模式
第二种方法:最大努力一次提交模式 但使用ChainedTransactionManager
ChainedTransactionManager处理流程
第三种方法:最大努力一次提交模式 但使用atomikos
遗留问题
应用场景
现在有个项目,要做数据迁移,要把A库中的 数据迁移到B库,以后新的功能都在B库上开发,两个库都是mysql的。但是很多旧的的项目 还在要使用A库的数据,所以需要一个过渡期,在写B库的同时 也要保证能写到A库。为了保证两个数据库的数据完整性和一致性,只能同时操作两个库,并保证操作的原子性。
问题描述
我们要保证多数据源 操作的原子性,就要使用分布式事物。幸好两个数据源都是同类型 mysql 库。不同类型的如 mysql 和 redis 之前同步要复杂点,这个后续给出解决方法。
使用spring 事物管理机制解决分布式事物问题。可以参考博文:http://www.open-open.com/lib/view/open1429863503010.html#articleHeader8。解决方案主要包括两大类:
(1)XA方式
(2)非XA方式
(3)用消息队列消除分布式事务
使用XA方式效率较低,使用消息队列消除分布式式事务又太过复杂。基于效率 和时间成本考虑,我选用spring的链式事务管理器 非XA方式 ChainedTransactionManager。它是最大努力一阶段提交模式中,一个粗糙的事务管理器实现仅仅是将一系列其他的事务管理器链接在一起,去实现事务同步。倘若业务处理成功,所有的事务将会提交, 否则它们都能回滚。最大努力一次提交模式的安全性不如XA事务但也是相当不错,因此能够承受风险获得较高的吞吐量收益。如果我们将关键业务处理服务设计为一个幕等式 (idempotent),这样发生错误的可能性也很小。
解决方法
多数据源配置
(1)数据源配置文件:
spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary
spring.datasource.primary.username=root
spring.datasource.primary.password=
spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary
spring.datasource.secondary.username=root
spring.datasource.secondary.password=
spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
(2)spring boot加载数据源
以下配置了两个数据源,但是没有配置事务管理。
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "dataSource")
@Qualifier("dataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource dataSource(www.089188.cn/) {
return DataSourceBuilder.create().build();
}
@Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(
@Qualifier("primaryDataSource"www.dfgj157.com) DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "secondaryJdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(
@Qualifier("secondaryDataSource") DataSource dataSource) {
(3)测试用例
我没有使用单元测试,因为单元测试里面如果加上了@Transactional 会自动回滚事务,需要在单元测试上面加上 @Rollback(false),但是这样就失去了测试的意义,我们就是要测试事务的原子性,不能手动设置事务的回滚方式。所以单独写了一个 Rest 接口用于调试如下:
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Autowired
PrimaryUserService primaryUserService;
@Autowired
SecondaryUserService secondaryUserService;
@Autowired
@Qualifier("primaryJdbcTemplate")
JdbcTemplate primaryJdbcTemplate;
@Autowired
@Qualifier("secondaryJdbcTemplate")
JdbcTemplate secondaryJdbcTemplate;
@RequestMapping(value =www.leyou1178.cn/ "add/{name}", method = RequestMethod.POST)
@ResponseBody
@Transactional
public String addUser(@PathVariable String name) {
int count = secondaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
Assert.isTrue(count == 0);//会抛异常
primaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
//用业务层封装下
//int count = primaryUserService.create(name);
//Assert.isTrue(count == 0);//会抛异常
//secondaryUserService.create(name);
33
单元测试
第一种方法:最大努力一次提交模式
但是不使用ChainedTransactionManager
(1)正常情况没有问题 ,都能写入数据。
@RequestMapping(value = "add/{name}", method = RequestMethod.POST)
@ResponseBody
@Transactional
public String addUser(@PathVariable String name) {
int count = secondaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
primaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
return name;
(2)如果出现异常,数据不能保持一致了。如下所示。虽然把他们用spring的事务注解放到了一起,但是当secondaryJdbcTemplate执行完并报错后,primaryJdbcTemplate就无法正常添加数据,但是secondaryJdbcTemplate却并不受影响。
@RequestMapping(value = "add/{name}", method = RequestMethod.POST)
@ResponseBody
@Transactional
public String addUser(@PathVariable String name) {
int count = secondaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
Assert.isTrue(count ==www.dfgjpt.com 0);//会抛异常
primaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
return name;
备注:事实上上面两个操作根本不受 @Transactional 注解的影响。因为单元测试里面如果加上了@Transactional 会自动回滚事务,需要在单元测试上面加上 @Rollback(false),但是上面的操作完全没有要回滚的意识。
第二种方法:最大努力一次提交模式 但使用ChainedTransactionManager
首先在spring boot 配置中添加如下内容:
@Bean
@Primary
public ChainedTransactionManager transactionManager(@Qualifier("primaryDataSource") DataSource primaryDataSource,
@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
DataSourceTransactionManager primaryTransactionManager = new DataSourceTransactionManager(primaryDataSource);
DataSourceTransactionManager secondaryTransactionManager = new DataSourceTransactionManager(
secondaryDataSource);
ChainedTransactionManager chainedTransactionManager = new ChainedTransactionManager(primaryTransactionManager,
secondaryTransactionManager);
(1) 正常情况没有问题 ,都能写入数据。如下:
(2) 如果spring业务层出现异常,数据还能保持一致
@RequestMapping(value = "add/{name}", method = RequestMethod.POST)
@ResponseBody
@Transactional
public String addUser(@PathVariable String name) {
int count = secondaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
Assert.isTrue(count == 0);//会抛异常
primaryJdbcTemplate.update("insert into USER(NAME) values(?)", name);
//用业务层封装下
//int count = primaryUserService.create(name);
//Assert.isTrue(count ==www.tianzunyule178.com 0);//会抛异常
//secondaryUserService.create(name);
return name;
ChainedTransactionManager处理流程
ChainedTransactionManager只是同时开启两个事务,自动的对两个事务,同时开启,同时提交(或回滚)。它对多个数据写数据,并不是一个原子操作,不能像XA那样保证对数据操作的完整性,一致性。
看源代码:它用一个列表来管理多个数据源的事务管理器。
用MultiTransactionStatus封装多个数据源的事务,统一管理。
逐个Commit 事务的时候,一旦发现某个事务不能commit,立刻回滚后面的事务。
最后尽最大努力回滚事务列表
spring分布式事务控制的更多相关文章
- Spring分布式事务实现概览
分布式事务,一直是实现分布式系统过程中最大的挑战.在只有单个数据源的单服务系统当中,只要这个数据源支持事务,例如大部分关系型数据库,和一些MQ服务,如activeMQ等,我们就可以很容易的实现事务. ...
- Spring分布式事务
[如何实现XA式.非XA式Spring分布式事务] [http://www.importnew.com/15812.html] 在JavaWorld大会上,来自SpringSource的David S ...
- 13 Spring 的事务控制
1.事务的概念 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必 ...
- 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制
spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...
- spring分布式事务学习笔记
最近项目中使用了分布式事务,本文及接下来两篇文章总结一下在项目中学到的知识. 分布式事务对性能有一定的影响,所以不是最佳的解决方案,能通过设计避免最好尽量避免. 分布式事务(Distributed t ...
- 如何实现XA式、非XA式Spring分布式事务
Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...
- 非XA式Spring分布式事务
Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...
- spring分布式事务学习笔记(1)
此文已由作者夏昀授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 分布式事务对性能有一定的影响,所以不是最佳的解决方案,能通过设计避免最好尽量避免. 分布式事务(Distrib ...
- Spring分布式事务实现
分布式事务是指操作多个数据库之间的事务,spring的org.springframework.transaction.jta.JtaTransactionManager,提供了分布式事务支持.如果使用 ...
随机推荐
- PWD简介与妙用(一个免费、随时可用的Docker实验室)
转载自 https://baiyue.one/archives/472.html 本文介绍下 PWD 的历史,并依据本站最近学习心得,经过多次尝试,终于打通了 Docker 与常规宝塔面板搭建,因此, ...
- python 产生随机数
Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ...
- C++ 内存分配操作符new和delete详解
重载new和delete 首先借用C++ Primer 5e的一个例子: string *sp = new string("a value"); ]; 这其实进行了以下三步操作: ...
- Map集合应用 取出一个字符串中字母出现的次数。如:字符串:"abcdekka27qoq" ,输出格式为:a(2)b(1)k(2)...
package com.swift; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import ...
- Android读书笔记二
本章讲到需要Android应用程序以及Android NDK程序来测试Linux驱动,所以所需要的工具都必须配备好.而且对工具的版本也是有一些要求,JDK,Eclipse,ADT,CDT,Androi ...
- NOIP模拟赛 高级打字机
[题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x. ...
- MHA
MHA 1. MHA简介 1.1 MHA工作原理总结为如下 1.2 MHA工具包介绍 2. 部署MHA 2.1 环境介绍 2.2 一主两从复制搭建 2.3 配置互信 2.4 下载MHA 2.5 安装M ...
- Linux网络配置指令
版权声明:本文为博主原创文章,未经博主允许不得转载. 原文地址: https://www.cnblogs.com/poterliu/p/6686799.html 重启网卡service network ...
- paper:synthesizable finit state machine design techniques using the new systemverilog 3.0 enhancements之fsm1各种style的timing/area比较
整体说,一般还是用2段式,再加上output encodecd/default -X技巧.
- Applied Nonparametric Statistics-lec7
Ref: https://onlinecourses.science.psu.edu/stat464/print/book/export/html/9 经过前面的步骤,我们已经可以判断几个样本之间是否 ...