当前位置: 首页 > article >正文

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

文章目录

  • 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);
        // 改日志1
        LogDo 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);
        // 改日志2
        LogDo 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 {
        // 改日志1
        LogDo 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);
        // 改日志2
        LogDo 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.kler.cn/a/504352.html

相关文章:

  • 【CSS】HTML页面定位CSS - position 属性 relative 、absolute、fixed 、sticky
  • Linux 服务器挖矿木马防护实战:快速切断、清理与加固20250114
  • c语言 --- 字符串
  • 【网络云SRE运维开发】2025第3周-每日【2025/01/14】小测-【第13章ospf路由协议】理论和实操
  • 《解锁鸿蒙Next系统人工智能语音助手开发的关键步骤》
  • UML系列之Rational Rose笔记八:类图
  • 使用中间件自动化部署java应用
  • Oracle 学习指南与资料分享
  • React 实战详细讲解:setState 是什么、如何更新及批量处理
  • Java IDEA中Gutter Icons图标的含义
  • 实现一个VSCode插件(从创建到发布)
  • android 内存泄露实战分析
  • 台湾省村里边界2018年4月更新arcgis数据shp格式内容分析测评
  • Unity ShaderGraph中Lit转换成URP的LitShader
  • 【数学】概率论与数理统计(四)
  • docker run一个镜像如何指定最大可使用的内存大小、cpu大小
  • 一.项目课题 <基于TCP的文件传输协议实现>
  • Linux下杂项设备驱动的编写
  • Elasticsearch技术标准解析与实践案例
  • 软路由如何实现电脑手机一机一IP
  • springboot 根据UUID生成唯一的短链接
  • 如何学好数据结构?
  • 大数据原生集群 (Hadoop3.X为核心) 本地测试环境搭建二
  • 如何备考PostgreSQL中级认证
  • 统计有序矩阵中的负数
  • STM32第6章、WWDG