• java中锁与@Transactional同时使用导致锁失效的问题


    示例代码

      @Transactional
        public void update(int id) {
            boolean lock = redisLock.lock(id);
            if (!lock) {
                throw new RuntimeException("当前人数过多,请稍后再试");
            }
            /*
              业务代码在该区域
             */
            redisLock.unlock(id);
        }
    

    在上面的代码中,我们同时使用了@transactional和redis分布式锁(其他锁同理,比如synchronized同步锁也会出现这个问题)

    问题分析

      上面这个例子是无法保证数据的一致性.由于spring的aop,会在update方法之前开启事务,之后再加锁,当锁住的代码执行完成后,再提交事务,因此锁住的代码块执行是在事务之内执行的,可以推断在代码块执行完时,事务还未提交,锁已经被释放,此时其他线程拿到锁之后进行锁住的代码块,读取的库存数据不是最新的。

    解决方法

      我们可以在update方法之前就加上锁,在还没有开事务之前就加锁,那么就可以保证线程的安全性,从而不会出现脏读和数据不一致性等情况.

       @RequestMapping("/execute")
        public void execute(int id) {
            boolean lock = redisLock.lock(id);
            if (!lock) {
                throw new RuntimeException("当前人数过多,请稍后再试");
            }
            service.update(id);
            redisLock.unlock(id);
        }
    
       @Transactional
        public void update(int id) {
            /*
              业务代码在该区域
             */
        }
    
  • 相关阅读:
    FPGA市场潜力有几多?
    FPGA前世今生(四)
    FPGA前世今生(三)
    FPGA前世今生(二)
    FPGA前世今生(一)
    嵌入式视频处理考虑(二)
    常用Linux操作命令
    混合开发学习路线
    Eclipse使用
    ECS的配置与使用
  • 原文地址:https://www.cnblogs.com/devise/p/10847575.html
Copyright © 2020-2023  润新知