自定义切面导致的事务失效问题

1、问题引出

在本地测试中,发现在一段被@Transaction注解标注的方法即使抛出了RunTimeException,数据库依然会有新的记录产生,也就是事务没有回滚,代码如下:

spring 自定义meiju spring 自定义 切面 不生效_spring 自定义meiju


多次检查事务相关都没有的配置都没有问题,然后在Spring的事务方法中,打上断点,看下具体的执行逻辑:

spring 自定义meiju spring 自定义 切面 不生效_自定义_02


后来发现,retVal = invocation.proceedWithInvocation(); 执行完后,没有进cache代码块,而是直接进入commitTransactionAfterReturning ,因此走了提交逻辑,那么明明抛出异常了为什么没有进cache呢?

原来是自定义的切面影响的,自定义的切面 也切了这个方法,并且如果发生异常,统一cache,返回一个统一的Result对象,因此走到这里的时候,已经没有异常了。最根本的原因就是方法抛出的异常被try-cach抓住了,因此没有回滚,只是这个try-cache比较隐晦,在aop的切面中,因此一时间没有发现。

spring 自定义meiju spring 自定义 切面 不生效_spring 自定义meiju_03


业务逻辑抛出的异常,被自定义切面抓取了,并且没有往外抛出,最终事务切面切到的方法没有抛出异常,因此提交了。

2、解决方法

对于解决方式,只要能让事物的切面获取到抛出的异常就行了,因此可以在自定义切面中再进行抛出,另外也可以手动控制事务,设置rollbackOnly属性。
在这里采取修改切面的执行顺序,选择将事务切面放到自定义切面的里层,这样抛出的异常首先被事务切面获取,所以事务生效,另外事务切面拿到异常后会重复抛出,不会影响自定义切面。
所有在自定义切面上加上@Order()注解,其中数字越小,优先级越高,越先执行。