在考虑使用分布式锁时,你还在为并发时的性能问题考虑吗?
还在为使用zk来实现分布式锁还是redis实现分布式锁而烦恼吗?
还在考虑锁的粒度问题吗,什么时候上锁,什么时候释放锁的问题而烦恼吗?
好了前面的问题自行去百度学习一下吧,我们今天来聊聊分布式锁与事务之间的那些事。
先举个栗子,看看以下这段代码锁释放方面是否存在问题:

是不是初看好像没问题,在try中获取锁,在finally中释放锁,常规操作
但是,我们想想一个场景:
故事来了:两个线程喝奶茶的故事,但奶茶只有一杯(锁)。
A线程、B线程
A对B说:1、我们可以一起开启事务一起happy吧
A对B说:2、我们一起那啥进入doQuality方法吧
A对B说:3、奶茶只有一杯,我喝吧,你就别喝了,获取得到分布式锁
A: 4、A喝着奶茶,执行对应的业务代码
A 5、A喝完奶茶,一滴不剩了,释放分布式锁
B 6、重点来了,B这时候也拿到了一杯奶茶,但是问题是奶茶只有一杯,获取得到分布式。
B 7、B重复着A喝奶茶的步骤,执行业务代码的操作
B 8、B喝完奶茶,一滴不剩了,释放分布式锁
A、A开始提交事务,奶茶喝完了。
B B线程提交事务,喝了杯假奶茶。
故事讲完了
通过以上两个线程的执行结果来看,我们发现同一杯奶茶被喝过两次,分布式锁并没有起到相应的效果(只有一杯奶茶)。因为在A喝完奶茶释放锁后提交事务之前的这个间隙时间里,B去获取分布式锁是能成功的,并且也会去执行相应的业务代码。然后A,B线程提交事务,这就是分布式锁与事务之间的锁间隙问题,导致的并发问题。
那么,问题来了,我们要如何去解决该问题呢?
方案一,在事务方法外加锁,try-catch-finaly,事务提交后释放锁?
那问题来了,我们如何控制锁的粒度?按方案一的处理方式来解决的话,会存在以下问题:
1、锁的粒度不好控制。释放锁也需要放在事务方法后去编写,对使用锁的姿势有一定的限制
方案二:事务内加锁,事务提交后的after-commint释放锁。
同方案一一样,都是事务提交后释放锁,但是,实现的方式稍微改变改变,如下代码:

在释放锁的release方法中向事务管理器注册一个事务完成监听器,当事务完成时再去执行监听器中的释放锁的操作。
这个再使用分布式锁的时候你可以用各种姿势来释放锁操作,反正最后真正执行的时候肯定是在事务提交后执行。
完..................................分割线
网友评论