spring声明实名式事务引发的生产问题

关注公众号:云下风澜 , 免费领取Java学习 面试资料

强调一下,笔者是很注意保护公司代码的,所以接下来都是用的伪代码。如果有什么问题可以和笔者私信沟通。

本次出问题的代码是一个审批接口的一部分逻辑。经笔者简化后(去掉各种各样的风骚判断+数据处理),最终剩下的逻辑如下(笔者重新简写的伪代码)。

	@Transactional //开启事物
    public void approval(){
       Boolean lock = getLock();//获取锁
       if(!lock){
           throw new BzException("获取锁失败");
       }
       try {
           Integer status = getStatus();//从数据库获取当前数据的状态
           //如果数据库的状态是待审批的话就将其改为已审批
           if(status == WAIT_APPROVAL){
                setStatus(APPROVALED);
           }else{
           		return;
           }
           addApprovalRecord();//新增一条审批记录
           return;
       }catch (Exception e){

       }finally {
            unLock();//释放锁
       }
    }
  • 首先是获取分布式锁。如果获取成功了就往下执行逻辑。
  • 然后获取当前单子的状态,发现状态如果是待审批的话,就将其改为已审批。然后释放锁,方法return。

本身直接看感觉方法也没什么问题,但恰恰越感觉没问题的地方就越容易出问题。
代码刚上线不久,笔者就被产品经理叫了过去,倒不是什么大问题。

产品经理:我怀疑你有bug,你这个为啥一个单子审批过后有两条审批记录。
笔者:我跟你说,我就没有过bug,是不是用户做了什么骚操作。

经过一番排查后,笔者顶着厚厚的脸皮承认了自己的bug。感觉自己的段位被人生生的打回了青铜。
bug原因如下。

  • 当两个人同时操作时,A获取锁成功,往下走,发现状态是待审批就正常进行审批,到下面return,笔者竟然忘记了,return的时候代码是先走finally的,所以代码在执行完逻辑走到了finally释放了锁。
  • 好巧不巧的在这个时候用户B也对这个单子进行了审核操作,进来之后发现没有锁,获取锁成功,往下走,然后获取状态发现是待审核(因为A操作的事物还没有提交)。
  • 这时用户A的操作执行了return,事物提交,将单子状态改成了已审核。
  • 但是B已经获取到当前单子的状态了,所以就继续正常审核了,结果状态是一致的,但是多了一条记录。

发现这个问题之后,笔者想到了两个解决方式,一个是将需要执行事务操作的审批部分代码,单独抽出一个方法后加上事务注解。

 public void approval(){
       Boolean lock = getLock();
       if(!lock){
           throw new BzException("获取锁失败");
       }
       try {
           ((zj) AopContext.currentProxy()).doApproval();
       }finally {
           unLock();
       }
        
       return;
    }

这样就可以当完全执行完审批操作这个事务时再释放锁

这里也有一个小知识点,在一个方法中调用另一个带有事物的方法时,要用获取当前对象的代理,通过代理类去调用带有事物的方法,否则事物不会生效(因为Spring的事物是通过代理和切面去实现的)

第二种方式就是不用Spring的事物注解,做手动事物管理,但是不推荐此方法,太low。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云下牧羊人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值