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 项目开发中更好地进行事务管理,保证业务逻辑的数据一致性和完整性。