一次并发请求引发的数据错误,使用mysql行级锁解决

/ 后端 / 没有评论 / 619浏览

1.伪代码及出问题原因

  @Transactional(rollbackFor = Exception.class)
  public void reward(){
       //查询邀请人数
       int total = invite.queryTotal(a);
       //如果超出限制返回
       if(total > 100){
          return;
       }  
       //绑定邀请关系
       invite.insert(a,b);    
       //其他逻辑... 
  }

原因就是多个并发请求同时进逻辑后invite.queryTotal(a)查出来的都是小于100,此时没有锁住资源,造成了多个请求都走了后面的插入逻辑造成数据错误;

2.解决

(1)在invite.queryTotal(a)该代码sql中加入for update使用排它锁;则并发请求后,第一个请求查询到该处时,其他请求都要等待第一个请求事务提交后才能往下执行;

(2)此处能用共享锁LOCK IN SHARE MODE吗,答案是不可以; 以上代码,当并发请求后,第一个请求走查询后,其他请求不会等待第一个请求事务的结束,会依然查询成功后往下走;

那么应用场景可以在,如有一个接口需要走查询逻辑,另一个接口是更新逻辑;当同时查询某个共同值时,查询不会阻塞互相等待锁释放;但是当查询没结束事务另一个接口更新时,则阻塞;或一个请求更新没结束事务,其他查询阻塞等待更新成功;