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

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)改为其他事务类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员大阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值