火柴人武林大会
156.74M · 2026-02-04
| 传播行为 | 当前有事务 | 当前无事务 | 异常回滚范围 |
|---|---|---|---|
| REQUIRED | 加入事务 | 新建事务 | 整个事务 |
| SUPPORTS | 加入事务 | 非事务运行 | 事务内操作 |
| MANDATORY | 加入事务 | 抛异常 | 整个事务 |
| REQUIRES_NEW | 新建事务 | 新建事务 | 仅新事务 |
| NOT_SUPPORTED | 挂起事务,非事务运行 | 非事务运行 | 无 |
| NEVER | 抛异常 | 非事务运行 | 无 |
| NESTED | 嵌套事务(保存点) | 新建事务 | 嵌套事务内 |
注意方法A调用有事务的方法B,需要用Spring 的代理对象,不然事务不生效。因为@Transactional底层是通过代理类实现事务的。
都是对于内部方法来说:
REQUIRED
内外层方法用相同的事务,同时提交和回滚
REQUIRES_NEW
内层独立事务,各自提交不影响
NESTED
内层方法有独立的存档点,内部抛异常指挥回滚到内部方法的开始状态,不会回滚外部的方法
不常用的:
SUPPORTS 外部有事务,那就用同一个事务,即使外部捕捉异常,也会回滚
NOT_SUPPORTED:内部方法报错,外部事务不会回滚,
MANDATORY 内外同一个事务,需要检查外部事务有事务,没有就会报错回滚(外部捕捉了异常,也会回滚)
NEVER 外部有事务,内部方法用事务会报错,外部事务回滚(如果外部吃掉异常,外部事务就不会回滚)
测试代码:
/**
* 都是对于内部方法来说:
* REQUIRED
* 内外层方法用相同的事务,同时提交和回滚
* REQUIRES_NEW
* 内层独立事务,各自提交不影响
* NESTED
* 内层方法有独立的存档点,内部抛异常指挥回滚到内部方法的开始状态,不会回滚外部的方法
*
* 不常用的:
* SUPPORTS 外部有事务,那就用同一个事务,即使外部捕捉异常,也会回滚
* NOT_SUPPORTED:内部方法报错,外部事务不会回滚,
* MANDATORY 内外同一个事务,需要检查外部事务有事务,没有就会报错回滚(外部捕捉了异常,也会回滚)
* NEVER 外部有事务,内部方法用事务会报错,外部事务回滚(如果外部吃掉异常,外部事务就不会回滚)
*
*/
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String trans() {
Book book = new Book();
book.setId(10);
book.setName("test");
boolean save = save(book);
log.info(save + "");
BookServiceImpl bookService = (BookServiceImpl) AopContext.currentProxy();
try {
bookService.otherTrans(10);
} catch (Exception e) {
}
return "ok";
}
@Transactional(propagation = Propagation.SUPPORTS)
public void otherTrans(int i) {
Book book = new Book();
book.setId(20 + i);
book.setName("otherTrans" + i);
save(book);
int a = 100 / 0;
}
// Propagation.NESTED 测试
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String trans1() {
Book book = new Book();
book.setId(10);
book.setName("test");
boolean save = save(book);
log.info(save + "");
BookServiceImpl bookService = (BookServiceImpl) AopContext.currentProxy();
for (int i = 0; i < 3; i++) {
try {
// NESTED 的方式,各自错了,回滚各自的内容,并不会影响其他事务
bookService.otherTrans(i);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
// int a = 1 / 0;
return "ok";
}
@Transactional(propagation = Propagation.NESTED)
public void otherTrans1(int i) {
Book book = new Book();
book.setId(20 + i);
book.setName("otherTrans" + i);
save(book);
if (i == 2) {
int a = 1 / 0;
}
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String trans2() {
Book book = new Book();
book.setId(10);
book.setName("test");
boolean save = save(book);
log.info(save + "");
BookServiceImpl bookService = (BookServiceImpl) AopContext.currentProxy();
try {
/*
这里一定要站在 是否是同一个事务中来看待这些传播行为
*/
// REQUIRED :即使吃掉异常,也会回滚,因为是同一个事务
// NESTED :吃掉异常,外部方法不会回滚,只会滚 内部 方法,因为有存档点
// REQUIRES_NEW :吃掉异常,外部方法不会回滚,只会滚 内部 方法,因为是不同事务
// NEVER :吃掉异常,外部方法不会回滚,内部方法报错不执行而已
bookService.otherTrans2(23);
} catch (Exception e) {
e.printStackTrace();
}
// int a = 1 / 0;
return "ok";
}
@Transactional(propagation = Propagation.NEVER)
public void otherTrans2(int i) {
Book book = new Book();
book.setId(20 + i);
book.setName("otherTrans" + i);
save(book);
int a = 1 / 0;
}