spring事务的各种传播特性结果(共有7*7=49种不同的情况)
结合spring源码测试事务的各种传播特性结果和总结(共有7*7=49种不同的情况)
本次来总结事务传播的特性,博主也是辛辛苦苦总结了将近一周,针对不同的类型都分别做了测试。
(各位看官看完请点个赞哟~~)
测试场景:两个方法,checkout(外层)方法调用updateStock(内层)方法,分别针对一下7种不同的事务进行测试
REQUIRED、NEVER、MANDATORY、SUPPORTS、NOT_SUPPORTED、REQUIRES_NEW、NESTED
一、先说说七种传播特性定义
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。
NESTED:如果业务方法在一个事务中执行,就在这个事务中嵌套,如果没有事务按着required执行,开启单独的事务,这种事务有多个事务的保存点,内部事务的回滚对外部事务没有影响
光看这几个概念啥也不清楚,就是看着玩玩而已,我们还是得需要自行去测试总结才能更加深入理解
二、49种各种类型测试及源码
| 外层方法事务传播特性(checkOut) | 内层方法事务传播特性(updateStock) | 总结
|
外层代码 | 内层代码 | main方法 | 外/内层均正常 | 内层异常(外层执行到内层以前都保持正常),外层正常 | 内层异常,外层正常(代码) | 外层异常(内层正常执行完毕后,外层主动抛出异常),内层正常![]() |
外层异常(内层正常执行完毕后,外层主动抛出异常),内层正常(代码) | spring源码步骤: | spring源码图片 | ||||
| REQUIRED | MANDATORY |
如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交, |
@Transactional(propagation = Propagation.“对应事务声明类型”) bookDao.updateStock(id); |
@Transactional(propagation = Propagation.“对应事务声明类型”)
|
public static void main(String[] args) { |
正常执行,并且数据库扣减库
|
内层抛出异常,执行异常回滚,外层事务进行回滚操作
|
|
外层抛出异常,此时内层到代码不会提交由外层统一提交事务,但外成抛出异常,此时内层到也跟着回滚 | 步骤1:通过上下文获取service并通过代理执行checkout方法,此时并非真正执行checkOut方法,而需要通过代理的形式获取,即通过CGLIB,如右图所示 |
|
|||||
| REQUIRED |
如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交, |
正常执行,并且数据库扣减库存 | 内层抛出异常,执行异常回滚,外层事务进行回滚操作 |
|
外层抛出异常,此时内层到代码不会提交由外层统一提交事务,但外成抛出异常,此时内层到也跟着回滚 | 步骤2:跳转到CglibAopProxy org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept该方法执行具体代理,此时代理对象是执行外层checkout方法 |
|
|||||||||
| SUPPORTS |
如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交, |
正常执行,并且数据库扣减库存 | 内层抛出异常,执行异常回滚,外层事务进行回滚操作 |
|
外层抛出异常,此时内层到代码不会提交由外层统一提交事务,但外成抛出异常,此时内层到也跟着回滚 | 步骤3:执行retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();通过调用proceed方法执行invoke,如图往下走到具体处理事务到方法invokeWithinTransaction |
|
|||||||||
| NEVER | 外层方法不能出现事务,如果出现事务则直接报错 |
|
步骤4: 继续往下走到声名式事务,获取transactionInfo,可以看出,此时执行的是外层方法,该方法为checkout,并且声明式事务类型为默认,PROPAGATION_REQUIRED,ISOLATION_DEFAULT | ![]()
|
||||||||||||
| NOT SUPPORTED |
外层方法中有事务,直接挂起,内层方法没有异常情况的话直接顺利执行, |
正常执行,并且数据库扣减库存 | 内层在执行库存以后抛出异常,此时会挂起当前事务,开启一个新的非事务状态,来执行库存的操作,因此内层异常抛出,内层还是会提交事务,不会触发回滚,而外层已经捕获到异常则进行异常回滚 |
|
外层抛出异常,而内层的方法正常执行,且不用回滚,外层只回滚当前事务 | 步骤4.1: 在createTransactionIfNecessary方法中通过status = tm.getTransaction(txAttr);获取事务的状态信息,创建一个事务之后,并且开启一个新事务,如右图2所示 |
|
|||||||||
| REQUIRED NEW | 如果外层方法中存在事务,内层方法在运行的时候会挂起外层事务并开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;如果内层方法中存在异常,内层事务会优先回滚,外层方法事务也会回滚,如果外层方法中存在异常,那么内层事务正常正常提交,而外层方法会进行回滚操作 | 正常执行,并且数据库扣减库存 | 内层会开启一个新的事务,同时也会挂起持有事务,内层抛出异常,直接回滚操作,外层捕获异常也跟着一起回滚 |
|
外层抛出异常,内层的事务不会收到回滚,因此内层事务会提交,外层的统一回滚 | 步骤4.2 :在prepareTransactionInfo中完成当前线程副本进行事务绑定 |
|
|||||||||
| NESTED |
如果外层方法中有事务,那么直接创建一个保存点,后续操作中如果没有异常情况, |
正常执行,并且数据库扣减库存 | 内层事务有异常,且会创建一个savePoint保存点,用于记录当前状态信息,此时内层抛出异常,会回滚到保存点,外层事务同时捕获异常进行回滚 |
|
外层事务抛出异常,此时内层事务正常执行,但是不会提交事务,交由外层事务进行统一提交,如果此时外层异常,内层会主动退回到savePoint | 步骤5:执行增强方法,即通过函数式接口定位到内层方法,即为updateStock方法,该逻辑和外层一样 |
|
|||||||||
| MANDATORY | MANDATORY | MANDATORY不可以作为外层事务,在运行的时候必须需要一个事务 | MANDATORY不可以作为外层事务,在运行的时候必须需要一个事务 |
步骤6:执行内层方法,此时也通过 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();到具体的invoke方法,从而找到invokeWithinTransaction |
|
|||||||||||
| REQUIRED | 步骤7:此时我们的内层方法也通过同样的形式获取到transactionInfo,如右图所示 |
|
||||||||||||||
| SUPPORTS | 步骤8:执行增强方法通过函数式接口,从拦截器索引判断是否还有下一层级需要走代理,此时没有,则返回 |
|
||||||||||||||
| NEVER | 步骤9:通过invokeJoinPoint反射获取目标方法,目标类 |
|
||||||||||||||
| NOT SUPPORTED | 步骤10:执行具体业务方法 |
|
||||||||||||||
| REQUIRED NEW | ||||||||||||||||
| NESTED | MANDATORY不可以作为外层事务,在运行的时候必须需要一个事务 | |||||||||||||||
| SUPPORTS | MANDATORY | 外层方法中如果不包含事务的话,那么内层方法在获取事务对象的时候直接报错,而外层方法中不包含事务,所以无需回滚 |
|
|||||||||||||
| REQUIRED | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务抛出异常,内层在判断外层是时候,判断是当前线程是否持有事务,而此时并没有,因此它会挂起一个空事务,开启一个新的事务,外层会捕获该事务,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 |
|
外层事务抛出异常,此时内层的事务是一个全新的事务,内层提交事务,外层事务回滚 | |||||||||||
| SUPPORTS | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务抛出异常,而此时内层事务已经提交,即使抛出异常也不会影响内层事务的回滚,但是外层事务捕获到该内层事务的异常,会进行回滚操作 |
|
外层事务抛出异常,而内层的事务已经提交不受影响,外层事务如果在抛出异常前有其他在当前外层同一个事务的操作库存,此时外层的库存操作不会收到影响,也会提交,不会回滚 | |||||||||||
| NEVER | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务抛出异常,而此时内层事务已经提交,即使抛出异常也不会影响内层事务的回滚,但是外层事务捕获到该内层事务的异常,会进行回滚操作 |
|
外层事务抛出异常,而内层的事务已经提交不受影响,外层事务如果在抛出异常前有其他在当前外层同一个事务的操作库存,此时外层的库存操作不会收到影响,也会提交,不会回滚 | |||||||||||
| NOT SUPPORTED | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务抛出异常,而此时内层事务已经提交,即使抛出异常也不会影响内层事务的回滚,但是外层事务捕获到该内层事务的异常,会进行回滚操作 |
|
外层事务抛出异常,而内层的事务已经提交不受影响,外层事务如果在抛出异常前有其他在当前外层同一个事务的操作库存,此时外层的库存操作不会收到影响,也会提交,不会回滚 | |||||||||||
| REQUIRED NEW | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务抛出异常,此时内层事务会回滚,外层事务捕获到内层事务会,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 外层事务抛出异常,而内层的事务已经提交不受影响,外层事务如果在抛出异常前有其他在当前外层同一个事务的操作库存,此时外层的库存操作不会收到影响,也会提交,不会回滚 | ||||||||||||
| NESTED | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务抛出异常,此时内层事务会回滚,外层事务捕获到内层事务,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 外层事务抛出异常,而内层的事务已经提交不受影响,外层事务如果在抛出异常前有其他在当前外层同一个事务的操作库存,此时外层的库存操作不会收到影响,也会提交,不会回滚 | ||||||||||||
| NEVER | MANDATORY | 外层方法中如果不包含事务的话,那么内层方法在获取事务对象的时候直接报错,而外层方法中不包含事务,所以无需回滚 |
|
|||||||||||||
| REQUIRED | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务会新建一个事务,内层事务抛出异常,此时内层事务进行回滚,那么外层事务会捕获异常,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 |
|
内层事务新建一个事务,那么内层事务不会受到外层事务的影响,内层事务正常提交完成。外层事务产生异常,此时如果在异常前有同一个外层事务管理下的数据库插入/修改操作,那么该事务已经提交无法回滚 | |||||||||||
| SUPPORTS | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务会新建一个事务,内层事务在插入库之后抛出异常,那么内层事务将不会回滚,外层事务捕获到内层事务抛出到异常会进行回滚操作 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| NEVER | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | ||||||||||||||
| NOT SUPPORTED | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | ||||||||||||||
| REQUIRED NEW | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务会创建一个新的事务,内层事务出现异常会回滚,外层事务捕获内层事务,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| NESTED | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务会创建一个新的事务,内层事务出现异常会回滚,外层事务捕获内层事务,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| NOT SUPPORTED | MANDATORY | 外层方法中如果不包含事务的话,那么内层方法在获取事务对象的时候直接报错,而外层方法中不包含事务,所以无需回滚 |
|
|||||||||||||
| REQUIRED | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务会新建一个事务,内层事务抛出异常,此时内层事务进行回滚,那么外层事务会捕获异常,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 外层事务抛出异常,而内层的事务已经提交不受影响,外层事务如果在抛出异常前有其他在当前外层同一个事务的操作库存,此时外层的库存操作不会收到影响,也会提交,不会回滚 | ||||||||||||
| SUPPORTS | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务会新建一个事务,内层事务在插入库之后抛出异常,那么内层事务将不会回滚,外层事务捕获到内层事务抛出到异常会进行回滚操作 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| NEVER | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务会新建一个事务,内层事务在插入库之后抛出异常,那么内层事务将不会回滚,外层事务捕获到内层事务抛出到异常会进行回滚操作 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| NOT SUPPORTED | 内外层方法都不包含事务的话,会以无事务的方法开始运行,每个数据库操作直接执行即可,如果出现异常情况,则后续的操作不会执行,但已经执行过的数据库操作不受任何影响 | 正常执行,并且数据库扣减库存 | 内层事务会新建一个事务,内层事务在插入库之后抛出异常,那么内层事务将不会回滚,外层事务捕获到内层事务抛出到异常会进行回滚操作 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| REQUIRED NEW | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务会创建一个新的事务,内层事务出现异常会回滚,外层事务捕获内层事务,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| NESTED | 外层方法中不包含事务,所以内层方法会新建一个事务,如果程序正常执行,那么事务会正常提交,如果内层方法中出现异常,则内层方法事务正常回滚,而外层事务不做任何处理,如果外层方法中出现异常,则内层方法事务正常提交,外层方法抛出异常 | 正常执行,并且数据库扣减库存 | 内层事务会创建一个新的事务,内层事务出现异常会回滚,外层事务捕获内层事务,如果外层事务在异事务之前做了其他插入数据库的操作,那么不会影响事务回滚 | 内层事务正常提交,外层事务抛出异常不会影响到内层事务,因为都已经不是同一个事务,外层事务在插入库之后抛出异常,那么该事务已经提交将不会回滚 | ||||||||||||
| REQUIRED NEW | MANDATORY | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 | 正常执行,并且数据库扣减库存 | 内层事务出现异常,外层事务会接收到内层事务抛出到异常,同时在外层事务统一进行回滚操作 | 内层事务正常执行完毕,但是没有提交事务,需要到外层事务统一进行提交,但是外层事务异常,那么内层和外层的事务将统一进行回滚 | |||||||||||
| REQUIRED | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 | 正常执行,并且数据库扣减库存 | 内层事务出现异常,外层事务会接收到内层事务抛出到异常,同时在外层事务统一进行回滚操作 | 内层事务正常执行完毕,但是没有提交事务,需要到外层事务统一进行提交,但是外层事务异常,那么内层和外层的事务将统一进行回滚 | ||||||||||||
| SUPPORTS | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 | 正常执行,并且数据库扣减库存 | 内层事务出现异常,外层事务会接收到内层事务抛出到异常,同时在外层事务统一进行回滚操作 | 内层事务正常执行完毕,但是没有提交事务,需要到外层事务统一进行提交,但是外层事务异常,那么内层和外层的事务将统一进行回滚 | ||||||||||||
| NEVER | 外层方法不能出现事务,如果出现事务则直接报错 |
|
||||||||||||||
| NOT SUPPORTED | 外层方法中有事务,直接挂起,内层方法没有异常情况的话直接顺利执行,如果内层方法有异常的话,那么内层方法中已经执行的数据库操作不会触发回滚,而外层方法的事务会进行回滚操作,同样,如果外层方法中出现了异常操作,那么内部方法是不会回滚的,只有外层事务才会回滚 | 正常执行,并且数据库扣减库存 | 内层事务会挂起当前事务,创建一个新的非事务用于数据库操作,当内层事务抛出异常,内层事务将不会进行回滚操作,外层事务捕获异常并且进行回滚 |
|
内层事务会挂起当前事务,创建一个新的非事务用于处理,数据库正常提交并不受到外层事务影响,而外层事务会回滚 | |||||||||||
| REQUIRED NEW | 如果外层方法中存在事务,内层方法在运行的时候会挂起外层事务并开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;如果内层方法中存在异常,内层事务会优先回滚,外层方法事务也会回滚,如果外层方法中存在异常,那么内层事务正常正常提交,而外层方法会进行回滚操作 | 正常执行,并且数据库扣减库存 | 内层事务会挂当前事务,并且开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;内层事务出现异常,则会优先回滚内层事务,内层事务回滚完毕后,外层事务捕获到异常,外层事务进行回滚 |
|
内层事务是一个新的事务,将不会受到外层事务到影响,内层事务正常提交完毕,如果外层事务出现异常,内层事务将不会受到回滚,同时外层事务会进行回滚操作 | |||||||||||
| NESTED | 如果外层方法中有事务,那么直接创建一个保存点,如果外层方法没有事务,那么就创建一个新的事务,后续操作中如果没有异常情况,那么会清除保存点信息,并且在外层事务中进行提交操作,如果内层方法中存在异常情况,那么会回滚到保存点,外层方法事务会直接进行回滚,如果外层方法中存在异常情况,那么会内层方法会正常执行,并且执行完毕之后释放保存点,并且外层方法事务会进行回滚 | 正常执行,并且数据库扣减库存 | 内层事务会创建一个savepoint保存点,内层事务没有提交,在外层事务进行一起提交事务;如果外层事务出现异常,那么会回滚到保存点,外层事务接收异常后进行事务回滚操作 |
|
外层事务抛出异常后,内层事务会正常执行,但是不会提交,并且释放保存点,在外层事务统一进行事务回滚 | |||||||||||
| NESTED | MANDATORY | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 | 正常执行,并且数据库扣减库存 | 内层事务出现异常后在外层事务统一进行回滚操作 | 内层事务正常执行完毕,但是没有提交事务,需要在外层事务一起提交,但是外层事务出现异常,同时内层外层事务一起回滚 | |||||||||||
| REQUIRED | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 | 正常执行,并且数据库扣减库存 | 内层事务出现异常后在外层事务统一进行回滚操作 | 内层事务正常执行完毕,但是没有提交事务,需要在外层事务一起提交,但是外层事务出现异常,同时内层外层事务一起回滚 | ||||||||||||
| SUPPORTS | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 | 正常执行,并且数据库扣减库存 | 内层事务出现异常后在外层事务统一进行回滚操作 | 内层事务正常执行完毕,但是没有提交事务,需要在外层事务一起提交,但是外层事务出现异常,同时内层外层事务一起回滚 | ||||||||||||
| NEVER | 外层方法不能出现事务,如果出现事务则直接报错 |
|
||||||||||||||
| NOT SUPPORTED | 外层方法中有事务,直接挂起,内层方法没有异常情况的话直接顺利执行,如果内层方法有异常的话,那么内层方法中已经执行的数据库操作不会触发回滚,而外层方法的事务会进行回滚操作,同样,如果外层方法中出现了异常操作,那么内部方法是不会回滚的,只有外层事务才会回滚 | 正常执行,并且数据库扣减库存 | 内层事务会挂起当前事务,创建一个新的非事务用于数据库操作,当内层事务抛出异常,内层事务将不会进行回滚操作,外层事务捕获异常并且进行回滚 |
|
内层事务会挂起当前事务,创建一个新的非事务用于处理,数据库正常提交并不受到外层事务影响,而外层事务会回滚 | |||||||||||
| REQUIRED NEW | 如果外层方法中存在事务,内层方法在运行的时候会挂起外层事务并开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;如果内层方法中存在异常,内层事务会优先回滚,外层方法事务也会回滚,如果外层方法中存在异常,那么内层事务正常正常提交,而外层方法会进行回滚操作 | 正常执行,并且数据库扣减库存 | 内层事务会挂当前事务,并且开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;内层事务出现异常,则会优先回滚内层事务,内层事务回滚完毕后,外层事务捕获到异常,外层事务进行回滚 |
|
内层事务是一个新的事务,将不会受到外层事务到影响,内层事务正常提交完毕,如果外层事务出现异常,内层事务将不会受到回滚,同时外层事务会进行回滚操作 | |||||||||||
| NESTED | 如果外层方法中有事务,那么直接创建一个保存点,如果外层方法没有事务,那么就创建一个新的事务,后续操作中如果没有异常情况,那么会清除保存点信息,并且在外层事务中进行提交操作,如果内层方法中存在异常情况,那么会回滚到保存点,外层方法事务会直接进行回滚,如果外层方法中存在异常情况,那么会内层方法会正常执行,并且执行完毕之后释放保存点,并且外层方法事务会进行回滚 | 正常执行,并且数据库扣减库存 | 内层事务会创建一个savepoint保存点,内层事务没有提交,在外层事务进行一起提交事务;如果外层事务出现异常,那么会回滚到保存点,外层事务接收异常后进行事务回滚操作 |
|
外层事务抛出异常后,内层事务会正常执行,但是不会提交,并且释放保存点,在外层事务统一进行事务回滚 | |||||||||||
现在面试常问的两个问题:
1、REQUIRED和NESTED回滚的区别
两种方式区别,最大的问题在于保存点的设置,很多同学会认为内部设置REQUIRED和NESTED效果是一样的,其实在外层方法对内层方法的异常情况在进行捕获的时候区别很大,两者报的异常信息都不同,使用REQUIRED的时候,会报Transaction rolled back because it has been marked as rollback-only信息,因为内部异常了,设置了回滚标记,外部捕获之后,要进行事务的提交,此时发现有回滚标记,那么意味着要回滚,所以会报异常,而NESTED不会发证这种情况,因为在回滚的时候把回滚标记清除了,外部捕获异常后去提交,没发现回滚标记,就可以正常提交了。
2、REQUIRED_NEW和REQUIRED区别
这两种方式产生的效果是一样的,但是REQUIRED_NEW会有新的连接生成,而NESTED使用的是当前事务的连接,而且NESTED还可以回滚到保存点,REQUIRED_NEW每次都是一个新的事务,没有办法控制其他事务的回滚,但NESTED其实是一个事务,外层事务可以控制内层事务的回滚,内层就算没有异常,外层出现异常,也可以全部回滚。





浙公网安备 33010602011771号