这里的事务传播属性都是针对于内部方法的事务来说的:
| 传播行为 | 当前有事务 | 当前无事务 | 异常回滚范围 |
|---|---|---|---|
| REQUIRED | 加入事务 | 新建事务 | 整个事务 |
| SUPPORTS | 加入事务 | 非事务运行 | 事务内操作 |
| MANDATORY | 加入事务 | 抛异常 | 整个事务 |
| REQUIRES_NEW | 新建事务 | 新建事务 | 仅新事务 |
| NOT_SUPPORTED | 挂起事务,非事务运行 | 非事务运行 | 无 |
| NEVER | 抛异常 | 非事务运行 | 无 |
| NESTED | 嵌套事务(保存点) | 新建事务 | 嵌套事务内 |
| 传播属性 | 含义 | 行为说明 | 是否始终开启新事务 | 外部无事务时 |
|---|---|---|---|---|
| REQUIRED | 默认值 | 支持当前事务,如果不存在则新建一个 | 否 | 新建事务 |
| SUPPORTS | 支持 | 支持当前事务,如果不存在则以非事务方式执行 | 否 | 非事务执行 |
| MANDATORY | 强制 | 支持当前事务,如果不存在则抛出异常 | 否 | 抛异常 |
| REQUIRES_NEW | 新建 | 挂起当前事务,新建一个独立的新事务 | 是 | 新建事务 |
| NOT_SUPPORTED | 不支持 | 挂起当前事务,以非事务方式执行 | 否(挂起) | 非事务执行 |
| NEVER | 永不 | 禁止事务,如果当前存在事务则抛出异常 | 否 | 非事务执行 |
| NESTED | 嵌套 | 在当前事务中创建一个嵌套事务(Savepoint机制) | 否 | 新建事务 |
注意方法A调用有事务的方法B,需要用Spring 的代理对象,不然事务不生效。因为@Transactional底层是通过代理类实现事务的。
案例展示:
注:
外部方法就是指外层第一个有事务的方法或是发起事务的方法(例子中一般是testxxx)
内部方法就是指 外部有事务的这个方法调用的内部方法(例子中的orderSave)
方法A调用有事务的方法B,需要用Spring 的代理对象,不然事务不生效。因为@Transactional底层是通过代理类实现事务的。
- 内部方法都使用:Propagation.REQUIRED
外部内部方法在同一个事务中,谁报错都会同时回滚,都成功才会同时提交;
这案例表现为,book表和 user_order 表同时插入数据或者没有数据;
@Autowired
BookService bookService;
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String testRequired() {
// 保存 book 表数据
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里调用其他有事务的方法
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService)AopContext.currentProxy();
// 这里即使 捕捉了异常,外部方法同样也会回滚,因为REQUIRED 来说,两个方法已经放在同一个事务中了
try {
userOrderService.orderSave();
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 模拟错误-回滚,如果是 orderSave 是 Propagation.REQUIRED,那么同一个事务,都会同时回滚
int a = 0;
int b = 10 / a;
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String orderSave() {
// case1(当前方法propagation = Propagation.REQUIRED):
// 如果外部方法 testRequired 已经有事务了,那么就加入外部的事务,相当于就是用同一个事务(提交或是回滚都一起),
// 如果外部方法 testRequired 没有事务,那么当前方法就自己创建事务,提交或是回滚 都和外部方法无关
// 保存 user_order 表数据
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
// 模拟错误-回滚,如果是 orderSave 是 Propagation.REQUIRED,那么同一个事务,都会同时回滚
// int a = 0;
// int b = 10 / a;
return "success";
}
- 内部方法使用:Propagation.REQUIRES_NEW
外部内部方法在不同的事务中,内部方法失败不会影响外部的事务,反之,如果外部方法报错,也不会影响内部方法的提交,因为是各自独立的事务;
这案例表现为,book表和 user_order 表可以只有一个表插入数据成功,另一个表插入数据失败;
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES)
public String testRequiredNew() {
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService)AopContext.currentProxy();
try {
// 异常捕捉了,内部方法失败不会影响外部的事务,因为这是两个独立的事务
// 反之,如果外部方法报错,也不会影响内部方法的提交,因为是各自独立的事务
userOrderService.orderSave();
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 模拟错误-回滚
// int a = 0;
// int b = 10 / a;
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public String orderSave() {
// case2(当前方法propagation = Propagation.REQUIRES_NEW):
// 不管外部方法有没有事务,当前都会新建一个事务,内部事务和外部事务各不影响,内部事务报错只会回滚内部方法,外部事务还是会正常提交,反之一样
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
int a = 0;
int b = 10 / a;
return "success";
}
-
内部方法使用:Propagation.SUPPORTS
内部方法的事务取决于外部方法的事务:
如果外部方法有事务,就加入外部方法的事务,用同一个事务(同回滚或提交);
如果外部方法没有事务,那大家都不用事务,那么内外部方法都不会有事务,就普通方法调用;
// 这里注释了外部方法的事务
// 这里表现为 都没有事务,外部方法 book 表插入了数据, 内部方法 user_order 没有插入数据
@Override
// @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String testSupports() {
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService)AopContext.currentProxy();
try {
// 异常捕捉了,内部方法失败不会影响外部的事务,因为这是两个独立的事务
// 反之,如果外部方法报错,也不会影响内部方法的提交,因为是各自独立的事务
userOrderService.orderSave();
} catch (Exception e) {
System.out.println(e.getMessage());
}
// 模拟错误-回滚
// int a = 0;
// int b = 10 / a;
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS)
public String orderSave() {
// case3(当前方法propagation = Propagation.SUPPORTS):
// 外部方法有事务,则用外部方法的事务,两个方法就在同一个事务中了,同时回滚和提交
// 外部方法 没有事务,则都没有事务,按普通方法逻辑处理
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
int a = 0;
int b = 10 / a;
return "success";
}
-
内部方法使用:Propagation.MANDATORY
内部方法的事务取决于外部方法的事务:
外部方法有事务,则用外部方法的事务,两个方法就在同一个事务中了,同时回滚和提交;
外部方法 没有事务,则内部方法抛异常;
// 这里注释了外部事务,那么调用内部方法的时候,就会抛异常
// 这里 book 表会有数据, user_order 没有数据
@Override
// @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String testMandatory() {
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService)AopContext.currentProxy();
userOrderService.orderSave();
// 模拟错误-回滚
// int a = 0;
// int b = 10 / a;
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.MANDATORY)
public String orderSave() {
// case4(当前方法propagation = Propagation.MANDATORY):
// 外部方法有事务,则用外部方法的事务,两个方法就在同一个事务中了,同时回滚和提交
// 外部方法 没有事务,则内部方法抛异常
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
int a = 0;
int b = 10 / a;
return "success";
}
-
内部方法使用:Propagation.NOT_SUPPORTED
外部方法有事务,则挂起事务,内部方法不参数事务,即使外部方法回滚,也不影响内部方法的数据;
外部方法 没有事务,就都没有事务,普通方法处理;
// 这里外部方法抛了异常,但是内部方法还是执行了
// 表现为 book 表没有数据,user_order 表有数据
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String testNotSupported() {
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService)AopContext.currentProxy();
userOrderService.orderSave();
// 模拟错误-回滚
int a = 0;
int b = 10 / a;
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NOT_SUPPORTED)
public String orderSave() {
// case5(当前方法propagation = Propagation.NOT_SUPPORTED):
// 外部方法有事务,则挂起事务,内部方法不参数事务,即使外部方法回滚,也不影响内部方法的数据
// 外部方法 没有事务,就都没有事务,普通方法处理
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
return "success";
}
-
内部方法使用:Propagation.NEVER
外部方法有事务,内部方法就会抛出异常;
外部方法 没有事务,就正常按照普通方法处理;
// 外部方法有事务,这里内部方法配置了 Propagation.NEVER,那么内部方法就会抛异常
// 表现为 book 表没有数据,user_order 表没有数据
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String testNever() {
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService)AopContext.currentProxy();
userOrderService.orderSave();
// 模拟错误-回滚
// int a = 0;
// int b = 10 / a;
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NEVER)
public String orderSave() {
// case6(当前方法propagation = Propagation.NEVER):
// 外部方法有事务,内部方法就会抛出异常
// 外部方法 没有事务,就正常按照普通方法处理
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
return "success";
}
-
内部方法使用:Propagation.NESTED
外部方法事务回滚,会导致内部事务一起回滚;
内部方法回滚,不会造成外部事务回滚;
// 外部方法有事务,这里内部方法配置了 Propagation.NESTED,那调用的内部方法,作为一个事务中的保存点
// 特点是:内部方法异常回滚,不会让外部方法回滚;但是外部方法回滚,内部方法会一起回滚!
// 表现为 book 表有数据,user_order 表没有数据
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public String testNested() {
Book book = new Book();
book.setName("English");
book.setCreateTime(LocalDateTime.now());
bookService.save(book);
// 这里一定要获取到代理对象来调用 orderSave,不然orderSave 的事务不生效
UserOrderService userOrderService = (UserOrderService) AopContext.currentProxy();
try {
userOrderService.orderSave();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return "success";
}
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
public String orderSave() {
// case7(当前方法propagation = Propagation.NESTED):
// 外部方法事务回滚,会导致内部事务一起回滚
// 内部方法回滚,不会造成外部事务回滚
UserOrder userOrder = new UserOrder();
userOrder.setUser("user1");
userOrder.setAmount(100);
save(userOrder);
// 模拟错误-回滚
int a = 0;
int b = 10 / a;
return "success";
}
/*
对一外部方法的加在 内部方法调用上的 try catch,
这里一定要站在 内外部方法是否是同一个事务中来看待这些传播行为:
REQUIRED :即使吃掉异常,也会回滚,因为是同一个事务
NESTED :吃掉异常,外部方法不会回滚,只会滚 内部 方法,因为有存档点
REQUIRES_NEW :吃掉异常,外部方法不会回滚,只会滚 内部 方法,因为是不同事务
NEVER :吃掉异常,外部方法不会回滚,内部方法报错不执行而已
*/
try {
userOrderService.orderSave();
} catch (Exception e) {
System.out.println(e.getMessage());
}