闲谭SpringBoot--ShardingSphere分布式事务探究

devtools/2025/1/18 3:26:29/

文章目录

  • 0. 背景
  • 1. 未分库分表
  • 2. 仅分表时
  • 3. 分库分表
    • 3.1 不涉及分库表
    • 3.2 涉及分库表,且分库表处于一个库
    • 3.3 涉及分库表,且分库表处于多个库
    • 3.4 涉及分库表,且运行中某库停机
  • 4. 小结

0. 背景

接上篇文章《闲谭SpringBoot–ShardingSphere分库分表探究》,我已经完成分库分表的项目搭建。

本篇探究在不同情况下,事务是否正常运作。

1. 未分库分表

针对不分库的user表,故意抛出异常,看看能否回滚。

执行前:
在这里插入图片描述
执行代码:

     /*** 在未分库分表的情况下,可以正常回滚*/@Transactional(rollbackFor = Exception.class)public int testWithNoDivide() throws Exception {UserDo user = new UserDo();user.setId("2");user.setName("testWithNoDivide");int re = userService.add(user);if (true) {throw new Exception("err");}return re;}

执行后,由于抛出异常,事务回滚,数据库中的内容并未改变。

测试通过。

2. 仅分表时

如果将log表按时间进行分表,我们看能否回滚。

首先验证只使用@Transactional(rollbackFor = Exception.class)能否回滚多个表:

	/*** 在仅分表的情况下,测试是否可以回滚*/@Transactional(rollbackFor = Exception.class)public int testWithTableDivide() throws Exception {// 改用户UserDo user = new UserDo();user.setId("2");user.setName("testWithTableDivide");int reUser = userService.add(user);// 改日志LogDo log = new LogDo();log.setId("111");log.setTime("2025-01-01 11:11:11");log.setContent("testWithTableDivide");int reLog = logService.add(log);// 抛出异常if (true) {throw new Exception("err");}return reUser + reLog;}

通过验证,发现是可以正常回滚的,所以在仅分表不分库的情况下,使用@Transactional(rollbackFor = Exception.class)足矣。

3. 分库分表

如果既分库、又分表,是否需要开启分布式事务呢?

我们分两步验证,首先验证不涉及分库的表时,其次验证涉及分库的表时。

3.1 不涉及分库表

此时对log分库分表,测试user是否能正常回滚:

	/*** 在未分库分表的情况下,可以正常回滚*/@Transactional(rollbackFor = Exception.class)public int testWithNoDivide() throws Exception {UserDo user = new UserDo();user.setId("2");user.setName("testWithNoDivide");int re = userService.add(user);if (true) {throw new Exception("err");}return re;}

这个应该是没有悬念的,不涉及分库的表,没必要开启分布式事务

3.2 涉及分库表,且分库表处于一个库

我们同时修改user表、log表,但是让user和log处于一个数据库ds0里面,测试能否回滚

  	/*** 涉及分库表,且分库表处于一个库*/@Transactional(rollbackFor = Exception.class)public int testDbDivdeButInOneDb() throws Exception {// 改用户UserDo user = new UserDo();user.setId("2");user.setName("testDbDivdeButInOneDb");int reUser = userService.add(user);// 改日志1LogDo log1 = new LogDo();log1.setId("111");log1.setTime("2025-01-01 11:11:11");log1.setContent("testDbDivdeButInOneDb");log1.setDepartId("0");int reLog1 = logService.add(log1);// 改日志2LogDo log2 = new LogDo();log2.setId("222");log2.setTime("2025-02-02 11:11:11");log2.setContent("testDbDivdeButInOneDb");log2.setDepartId("0");int reLog2 = logService.add(log2);// 抛出异常if (true) {throw new Exception("err");}return reUser + reLog1 + reLog2;}

正常回滚,说明当表在一个库中时,使用@Transactional(rollbackFor = Exception.class)即可。

3.3 涉及分库表,且分库表处于多个库

我们再构造一个在不同库的例子,看能否回滚。

	/*** 涉及分库表,且分库表处于多个库*/@Transactional(rollbackFor = Exception.class)public int testDbDivdeButInTwoDb() throws Exception {// 改日志1LogDo log1 = new LogDo();log1.setId("111");log1.setTime("2025-01-01 11:11:11");log1.setContent("testDbDivdeButInOneDb");log1.setDepartId("0");//在库ds0中!int reLog1 = logService.add(log1);// 改日志2LogDo log2 = new LogDo();log2.setId("222");log2.setTime("2025-02-02 11:11:11");log2.setContent("testDbDivdeButInOneDb");log2.setDepartId("1");//在库ds1中!int reLog2 = logService.add(log2);// 抛出异常if (true) {throw new Exception("err");}return reLog1 + reLog2;}

实测证明依然回滚。

3.4 涉及分库表,且运行中某库停机

我们启动项目后,将ds1停止运行,然后测试,依然可以。

4. 小结

经查询文档,在不指定TransactionType,默认采用的TransactionType.LOCAL枚举值,这个用法已经够用了。

可以通过@ShardingTransactionType(TransactionType.XA)改为其他事务类型。


http://www.ppmy.cn/devtools/151448.html

相关文章

计算机网络(四)——网络层

目录 一、功能 二、IP数据报分片 三、DHCP动态主机配置协议 四、网络地址转换(NAT)技术 五、无分类编址CIDR 六、ARP地址解析协议 七、ICMP网际控制报文协议 八、IPv4和IPv6的区别 九、IPv4向IPv6的两种过渡技术——双栈协议和隧道技术 十、路由…

深入Node.js集群:原理、优势与搭建实战,如何应对高并发

文章目录 一、Node.js 集群简介二、Node.js 集群原理剖析2.1 主从模型2.2 负载均衡机制2.3 进程间通信(IPC) 三、Node.js 集群优势详解3.1 性能提升3.2 高可用性3.3 资源利用率优化 四、Node.js 集群搭建实战4.1 准备工作4.2 创建主控制节点4.3 工作节点…

文件操作的训练(python)

一、在文件夹中新建多个文件并写入内容 #写入函数 def file_write(file_name):#打开文件fileopen(file_name,"w")#写入内容file.write("Hello world")#关闭文件file.close() import os #新建一个文件夹"images" os.mkdir("images") #…

Golang|单机并发缓存

var m sync.Mutex //sync.Mutex 是一个互斥锁,可以由不同的协程加锁和解锁。 //sync.Mutex 是 Go 语言标准库提供的一个互斥锁 //当一个协程(goroutine)获得了这个锁的拥有权后,其它请求锁的协程(goroutine)就会阻塞在 Lock() 方法的调用上,直…

Spring Boot中使用AOP实现权限管理

权限管理的实现方法有很多种,也有很多集成不错的框架。现在用AOP和自定义注解实现一个简单易理解的权限管理~ 默认已经有做好了RBAC(role based access control),基于角色的访问控制。就是数据库中已经有了用户表,角色表,权限表…

MiniCPM-o 2.6:开源大型语言模型在多模态任务上超越GPT-4o和Claude 3.5

MiniCPM-o 2.6是一款开源的大型语言模型(LLM),其在多模态任务上的表现令人瞩目,成功超越了GPT-4o和Claude 3.5等业界知名模型。以下是对MiniCPM-o 2.6的详细介绍: 一、卓越的多模态能力 MiniCPM-o 2.6采用了先进的端…

ElasticSearch的劈山斧-自定义评分

ElasticSearch自定义评分 一、适用的场景 1.基本介绍 ES的使用中,ES会对我们匹配文档进行相关度评分。但对于一些定制化的场景,默认评分规则满足不了我们的要求。这些定制化场景,ES也是推出了自定义评分方式来进行支持。可以使用ES提供的一…

Go语言之路————条件控制:if、for、switch

Go语言之路————if、for、switch 前言ifforswitchgoto和label 前言 我是一名多年Java开发人员,因为工作需要现在要学习go语言,Go语言之路是一个系列,记录着我从0开始接触Go,到后面能正常完成工作上的业务开发的过程&#xff0…