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

示例代码

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

<small>在上面的代码中,咱们同时使用了@transactional和redis分布式锁(其余锁同理,好比synchronized同步锁也会出现这个问题)</small>redis

问题分析

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

解决方法

  咱们能够在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) {
        /*
          业务代码在该区域
         */
    }
相关文章
相关标签/搜索