前言:今天碰到了@Transactional 注解失效的情况,总结了以下的失效原因。
1、@Transactional注解作用在非public修饰的方法上,会失效。
失效原因:在Spring AOP代理时,TransactionInterceptor(事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy的内部类)的Intercept方法或JDKDynamicAopProxy的invoke方法会间接调用AbstractFallbackTransationAttributeSource的computeTransactionAttribute方法,获取@Transactional注解的事务配置信息。
2、@Transactional注解属性propagation设置错误导致注解失效
失效原因:配置错误, PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER三种事务传播方式不会发生回滚。
3、@Transactional注解属性rollbackFor设置错误导致注解失效
rollbackFor可以指定能够触发事务回滚的异常类型。Spring默认抛出了unchecked异常(继承自RuntimeException)或者Error才会回滚事务。若事务中抛出了其他类型的异常,但却期望Spring能够回滚事务,就需要指定rollbackFor属性,否则就会失效。
4、 同一类中方法调用,导致@Transactional失效
比如类demo中有方法A和B,方法B中使用@Transactional注解,方法A没有注解,但是demo类通过方法A调用方法B,像这种间接调用会导致方法B中的@Transactional事务注解失效。
失效原因:只有当事务方法被当前类以外的代码调用时,才会有Spring生成的代理对象管理。(Spring AOP代理机制造成的)。
5、多线程任务可能导致@Transaction案例失效
失效原因:线程不属于Spring托管,故线程不能够默认使用Spring的事务,也不能获取Spring注入的bean,在被Spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。
6、异常被方法内catch捕获导致@Transactional失效
比如B方法内部抛了异常,而A方法此时try-catch了B方法的异常,则该事务不能正常回滚。
失效原因:因为B方法中抛出异常以后,标识当前事务需要rollback,但是A方法中由于你手动的捕获这个异常并进行处理,A方法认为当前事务应该正常commit,此时就出现前后不一致,会抛出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only异常。