分布式锁和事务一起使用失效
原因: 在事务中使用redis分布式锁,方法一旦执行事务生效,接着是redis分布式锁生效,代码执行完后释放redis分布式锁、然后提交事务数据,最后事务结束。在这个过程中事务没有提交之前分布式锁已经被释放,导致分布式锁失效
解决:在调用事务方法之前先加分布式锁
@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方法之前就加上锁,在还没有开事务之前就加锁,那么就可以保证线程的安全性,从而不会出现脏读和数据不一致性等情况.
业务超时执行
锁失效时间设置问题
锁定了10s后过期,但业务执行了30s(可能碰到fullgc,死循环等场景)。
主从切换问题
业务1从主获取锁,此时主挂机了,从晋升为主,恰好此时从未同步这个锁的值 。