Spirng篇-Spring中事务失效的场景

882字

Spring 中事务失效场景学习笔记

在 Spring 开发中,事务管理是保证数据一致性和完整性的重要手段,但在某些场景下事务会失效。以下是常见的事务失效场景及其分析:

一、异常捕获处理

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Transactional
public void update(Integer from, Integer to, Double money) {
    try {
        // 转账的用户不能为空
        Account fromAccount = accountDao.selectById(from);
        // 判断用户的钱是否够转账
        if (fromAccount.getMoney() - money >= 0) {
            fromAccount.setMoney(fromAccount.getMoney() - money);
            accountDao.updateById(fromAccount);

            // 异常
            int a = 1/0; 

            // 被转账的用户
            Account toAccount = accountDao.selectById(to);
            toAccount.setMoney(toAccount.getMoney() + money);
            accountDao.updateById(toAccount);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

失效原因

事务通知只有捕捉到目标抛出的异常,才能进行后续的回滚处理。如果目标自己处理掉异常,事务通知无法知悉,事务不会回滚,从而导致事务失效。

解决方案

在 catch 块添加throw new RuntimeException(e)抛出异常,让事务通知能够捕捉到异常进行回滚。

二、抛出检查异常

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Transactional
public void update(Integer from, Integer to, Double money) throws FileNotFoundException {
    // 转账的用户不能为空
    Account fromAccount = accountDao.selectById(from);
    // 判断用户的钱是否够转账
    if (fromAccount.getMoney() - money >= 0) {
        fromAccount.setMoney(fromAccount.getMoney() - money);
        accountDao.updateById(fromAccount);

        // 读取文件
        new FileInputStream("dddd"); 

        // 被转账的用户
        Account toAccount = accountDao.selectById(to);
        toAccount.setMoney(toAccount.getMoney() + money);
        accountDao.updateById(toAccount);
    }
}

失效原因

Spring 默认只会回滚非检查异常(继承自RuntimeException及其子类),对于检查异常(如FileNotFoundException 等受检异常),默认情况下不会触发事务回滚,导致事务失效。

解决方案

配置rollbackFor属性,在@Transactional注解中指定rollbackFor=Exception.class ,这样 Spring 就会对指定的异常类型进行事务回滚。

三、非 public 方法

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Transactional(rollbackFor = Exception.class)
void update(Integer from, Integer to, Double money) throws FileNotFoundException {
    // 转账的用户不能为空
    Account fromAccount = accountDao.selectById(from);
    // 判断用户的钱是否够转账
    if (fromAccount.getMoney() - money >= 0) {
        fromAccount.setMoney(fromAccount.getMoney() - money);
        accountDao.updateById(fromAccount);

        // 读取文件
        new FileInputStream("dddd"); 

        // 被转账的用户
        Account toAccount = accountDao.selectById(to);
        toAccount.setMoney(toAccount.getMoney() + money);
        accountDao.updateById(toAccount);
    }
}

失效原因

Spring 为方法创建代理、添加事务通知等操作的前提条件是该方法是public的。如果方法不是public ,Spring 的事务管理机制无法正常工作,导致事务失效。

解决方案

将方法的访问修饰符改为public ,确保 Spring 能够正确地为其添加事务通知并进行事务管理。

掌握这些事务失效场景及其解决方案,有助于在 Spring 项目开发中更好地进行事务管理,保证业务逻辑的数据一致性和完整性。

如对内容有异议,请联系关邮箱2285786274@qq.com修改