关于spring同一个类中方法调用事物失效

关于spring同一个类中方法调用事物失效

  • 新人小白工作期间随笔记录
    • 问题起源
    • 解决方案一:
    • 引发新问题
    • 解决方案二:
    • 实际测试结果:
    • 研究@Transactional注解失效
    • 原因
    • 最终解决

新人小白工作期间随笔记录

问题起源

在与第三方系统交互,系统设计为与第三方系统交互成功后提交事物,完成本次操作。生产环境中发现第三方系统长时间无响应,造成事物长时间无法提交,用户再次刷新页面填写数据进行重复提交。由于业务问题,数据库中唯一索引无法使用。

解决方案一:

使用redis在service中加锁,在第三方系统响应后释放锁

引发新问题

锁是放在service层代码中,造成锁释放的时候,事物尚未提交,此时恰好用户在页面再次发起请求,仍会出现重复提交问题。

解决方案二:

  1. controller加锁 ,调用service前加锁,事物提交后释放锁;
  2. 在写一个新的service方法A,方法A上不使用@Transactional注解,在这个方法内加锁调用业务方法B,在B上添加@Transactional注解,这样B方法事物提交后释放锁;
@Override
public void A(){
	lock();
	B();
	unlock();
	
}
@Override
@Transactional
public void B(){
	insert();
	webservcice-->调用第三方
}

实际测试结果:

方案二的第一种可以解决此问题
但是第二种方法B报错,事物不会回滚,@Transactional注解失效。

研究@Transactional注解失效

按照理论来说分三种情况:

  1. 方法A加上@Transactional方法B加上@Transactional注解,发生runtime异常方法A,B事物统一回滚
  2. 方法A加上@Transactional方法B不加@Transactional注解,发生runtime异常方法A,B事物统一回滚;
  3. 方法A不加@Transactional方法B加上@Transactional注解,发生runtime异常方法A,B事物统一回滚;

实际测试证明1,2没有问题,3中的事物不生效

原因

spring在扫描bean的时候,会扫描方法上的@Transactional注解,如果有会生成一个代理子类,这个代理类是继承自这个bean的,当有注解的方法被调用时会先启动transaction,如果是当前类中的方法调用当前类的其他方法,那么调用时不会通过代理类调用而是直接调用那个bean,因此spring无法对事物的传播行为做处理。

最终解决

新建一个service N,在N新建方法C,不添加@Transactional注解,调用业务代码方法,调用前加锁,调用后事物提交,然后释放锁。

你可能感兴趣的:(spring事物传播失效)