当前位置: 首页 > 图灵资讯 > 技术篇> 分析spring事务@Transactional注解在同一个类中的方法之间调用不生效的原因及解决方案

分析spring事务@Transactional注解在同一个类中的方法之间调用不生效的原因及解决方案

来源:图灵教育
时间:2023-06-12 09:25:13

问题:

在Spring管理项目中,方法A使用Transactional注释,试图实现事务性。但是,当同一class中的方法B调用方法A时,会发现方法A中的异常不再导致回滚,即事务失效。

当该方法被同一类调用时,spring无法将该方法添加到事务管理中。

让我们来看看堆栈日志在生效和不生效时的比较。

分析spring事务@Transactional注解在同一个类中的方法之间调用不生效的原因及解决方案_解决方法

通过比较两个调用堆栈,我们可以看到spring@transactional事务生效的前提之一是在调用方法之前通过拦截器transactioninterceptor,也就是说,只有通过transactioninterceptor 将LJQ添加到spring事务管理中,查看spring源码即可看到,在AdvisedSuport中.getinterceptorsandynamicinterceptionadvice方法将从调用方法中获得@transactional注释。如果有注释,则启用事务,否则不启用。

分析spring事务@Transactional注解在同一个类中的方法之间调用不生效的原因及解决方案_方法调用_02

这种方法是通过SpringAOP类Cglibaoproxy内部类Dynamicadvisedinterceptor调用的,而Dynamicadvisedinterceptor继承了Methodinterceptor,用于调用拦截方法,并从中获得调用链。

如果在同一类中调用方法,则不会被方法拦截器拦截,因此事务不起作用。必须将该方法放入另一类,并通过spring注入。

原因:

Transactional是Spring提供的事务管理注释。

重点在于,Spring采用动态代理(AOP)实现对bean的管理和切片,为我们的每个class生成代理对象。只有在代理对象之间调用时,才能触发切面逻辑

在同一个class中,方法B调用方法A,调用原对象的方法,而不是代理对象。因此,Spring不能切断此调用,也不能通过注释来保证事务性。

也就是说,如果在同一类中调用方法,则不会被方法拦截器拦截,因此事务不会工作。

解决方法1:

将事务方法放入另一类(或单独打开一层,命名为“事务层”)进行调用,即符合在对象之间调用的条件。

解决方法2:

获取本对象的代理对象,然后调用。具体操作如下:

1) Spring-content.在xml上下文中,增加配置:

2) 在xxxserviceimpl中使用(xxxService)(AopContext.currentProxy(),获得xxxservice的代理类,然后调用事务方法,强行通过代理类,激活事务截面。

解决方法3:

大多数情况下,该方法调用并希望激活事务,因为同一方法包括DAO操作和I/O等耗时操作,不希望耗时的I/O导致事务耗时过长(例如,新产品需要同时写入库存)。此时,I/O可以进行异步操作(如添加线程池),即使添加了事务,也不会导致事务过长,问题可以很容易地解决。

解决方法4:

用@Autowired 注入自己 然后用注入的bean调用自己的方法