曹耘豪的博客

Spring之嵌套事务回滚的处理

  1. 方法解释
  2. case分析
  3. 解决

方法解释

case分析

被嵌套的事务没有异常处理,此时事务正常处理,插入ab的操作都会回滚,也是大多数的情况,此时没有问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@GetMapping("/test")
public void test() {
transactionExecutor.execute(() -> {

repo.insert(a);

transactionExecutor.execute(() -> {
repo.insert(b);
throw new IllegalStateException();
});

repo.insert(c);

});
}

下面是被嵌套的事务被try包住,此时插入c时报错(即使没有c操作,在外部事务提交时也一样会报错),因为此时事务已处于回滚状态,所以插入a的操作也被回滚了。

看起来是合理的,但如果在插入c前还有其他逻辑,可能就会有问题,并且既然已经使用try包住,那么我们一定是希望try内部发生异常应该不影响try外的逻辑,但目前是影响了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@GetMapping("/test")
public void test() {
transactionExecutor.execute(() -> {

repo.insert(a);

try {
transactionExecutor.execute(() -> {
repo.insert(b);
throw new IllegalStateException();
});
} catch (Exception e) {
}

repo.insert(c); // 【报错】

});
}

解决

新增一个方法(transactionExecutor.newTransaction),用于开启Propagation.REQUIRES_NEW的事务

使用newTransaction,包住被嵌套的方法,使事务隔离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@GetMapping("/test")
public void test() {
transactionExecutor.execute(() -> {

repo.insert(a);

try {
transactionExecutor.newTransaction(() -> {
transactionExecutor.execute(() -> { // 【1】
repo.insert(b);
throw new IllegalStateException();
});
})
} catch (Exception e) {
}

repo.insert(c);

});
}
   /