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