@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) { /* 业务代码在该区域 */ }