1 如何使用
在方法上加Transactional标签 并配置propagation 默认为REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
Propagation 枚举有7种
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
2 每种意思
枚举 | 小写 | 含义 | |
REQUIRED | required | 必须的 | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
SUPPORTS | supports | 支持 | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
MANDATORY | mandatory | 强制性的,义务的 | 使用当前的事务,如果当前没有事务,就抛出异常。 |
REQUIRED NEW | required new | 新建事务 挂起当前事务 | 新建事务,如果当前存在事务,把当前事务挂起。 |
NOT SUPPORTED | not supports | 不支持 | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
NEVER | never | 非事务执行 发现事务抛出异常 | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
NESTED | nested | 嵌套 | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
3 相互关系
A方法调用B方法,AB方法都有事务,并且传播特性不同,那么A如果有异常,B怎么办,B如果有异常,A怎么办?
外层方法事务传播特性 | 内层方法事务传播特性 | 执行情况 |
REQUIRED | MANDATORY | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交, 如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 |
REQUIRED | ||
SUPPORTS | ||
NEVER | 外层方法不能出现事务,如果出现事务则直接报错 | |
NOT SUPPORTED | 外层方法中有事务,直接挂起,内层方法没有异常情况的话直接顺利执行, 如果内层方法有异常的话,那么内层方法中已经执行的数据库操作不会触发回滚, 而外层方法的事务会进行回滚操作,同样,如果外层方法中出现了异常操作, 那么内部方法是不会回滚的,只有外层事务才会回滚 | |
REQUIRED NEW | 如果外层方法中存在事务,内层方法在运行的时候会挂起外层事务并开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;如果内层方法中存在异常,内层事务会优先回滚,外层方法事务也会回滚,如果外层方法中存在异常,那么内层事务正常正常提交,而外层方法会进行回滚操作 | |
NESTED | 如果外层方法中有事务,那么直接创建一个保存点,后续操作中如果没有异常情况, 那么会清除保存点信息,并且在外层事务中进行提交操作, 如果内层方法中存在异常情况,那么会回滚到保存点,外层方法事务会直接进行回滚, 如果外层方法中存在异常情况, 那么会内层方法会正常执行,并且执行完毕之后释放保存点,并且外层方法事务会进行回滚 | |
MANDATORY | MANDATORY | MANDATORY不可以作为外层事务,在运行的时候必须需要一个事务,因此后续的 |
REQUIRED | ||
SUPPORTS | ||
NEVER | ||
NOT SUPPORTED | ||
REQUIRED NEW | ||
NESTED | ||
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 | 如果外层方法中有事务,那么直接创建一个保存点,如果外层方法没有事务,那么就创建一个新的事务,后续操作中如果没有异常情况,那么会清除保存点信息,并且在外层事务中进行提交操作,如果内层方法中存在异常情况,那么会回滚到保存点,外层方法事务会直接进行回滚,如果外层方法中存在异常情况,那么会内层方法会正常执行,并且执行完毕之后释放保存点,并且外层方法事务会进行回滚 | |
NESTED | MANDATORY | 如果程序正常执行,那么内层事务不会提交,在外部事务中统一进行事务提交,如果内层事务,或者外层事务中出现异常情况,那么会在外层事务的处理中统一进行异常回滚 |
REQUIRED | ||
SUPPORTS | ||
NEVER | 外层方法不能出现事务,如果出现事务则直接报错 | |
NOT SUPPORTED | 外层方法中有事务,直接挂起,内层方法没有异常情况的话直接顺利执行,如果内层方法有异常的话,那么内层方法中已经执行的数据库操作不会触发回滚,而外层方法的事务会进行回滚操作,同样,如果外层方法中出现了异常操作,那么内部方法是不会回滚的,只有外层事务才会回滚 | |
REQUIRED NEW | 如果外层方法中存在事务,内层方法在运行的时候会挂起外层事务并开启一个新的事务,如果程序正常执行,则内层方法优先事务提交,然后外层方法再提交;如果内层方法中存在异常,内层事务会优先回滚,外层方法事务也会回滚,如果外层方法中存在异常,那么内层事务正常正常提交,而外层方法会进行回滚操作 | |
NESTED | 如果外层方法中有事务,那么直接创建一个保存点,如果外层方法没有事务,那么就创建一个新的事务,后续操作中如果没有异常情况,那么会清除保存点信息,并且在外层事务中进行提交操作,如果内层方法中存在异常情况,那么会回滚到保存点,外层方法事务会直接进行回滚,如果外层方法中存在异常情况,那么会内层方法会正常执行,并且执行完毕之后释放保存点,并且外层方法事务会进行回滚 | |
如果自己动手把每一种情况都演示了,其实挺好理解的,关键是大家舍不舍得花费时间一个一个去验证,在面试过程中,可能会经常问一下两个问题: 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其实是一个事务,外层事务可以控制内层事务的回滚,内层就算没有异常,外层出现异常,也可以全部回滚。 |