redis分布式锁在MySQL事务代码中使用,没控制好并发原因

主要是原因:

1、MySQL的事务隔离机制为:重复读(主因)

2、分布式锁的释放在事务提交前(这个并发高时,时间差也是出现问题的源点)

排查代码(分布式锁+事务下面代码不是很合理)如下:

发现事务service中,获得redis分布式锁后,进行了数据库查询,根据数据查询出的结果进行了限制,同时事务提交前的finally中进行了提前释放分布式redis锁。

1、先说第一个分布式锁中进行数据库查询根据返回count进行处理的问题:

查看数据的事务隔离级别,SELECT @@tx_isolation;发现系统中是repeatable read(重复读),MySQL默认。

重复读:是事务开始时,便会创建快照(时间点 row trx_id,如果事务中有多个表,表查询的快照点都是事务中操作第一张表的时间点的快照),在同一个事务中查询同样的语句,返回的结果一致。MySQL是采用MCVV视图机制实现重复读

InnoDB 在实现 MVCC(数据库的多版本并发控制) 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。

更多的重复读以及回滚,可以参考https://blog.csdn.net/Srodong/article/details/88820378

出现没控制住的原因进程图如下:

事务A开启时,另外一个事务B未结束,当B释放锁提交事务,将坑位占用剩余0,此时事务A中恰好拿到锁,但是查询数据库时,坑位还是事务开始时的剩余1个(可重读的隔离级别下,B事务的提交数据对A不可见),所以导致1个坑位2个人占的情况。

解决办法,将隔离级别改为:读提交。

2、分布式锁在事务提交前进行释放的问题:

事务是在service方法中,将释放锁的代码上提到controller层进行处理,这样就是事务提交后再释放锁。

3.redis中setIfAbsent、exprie两个方法是两行代码,这样会出现设置的key长久存在问题,需要放同一个事务中,不过这个问题在redis2.1版本后,是一行代码解决。

https://segmentfault.com/a/1190000017933697?utm_source=tag-newest

4.更多的分布式锁的使用可以参看另外一篇文章分布式锁的使用:

https://blog.csdn.net/seapeak007/article/details/97814460

 

------------------------------------------------------------------------------------

数据库改为读重复的隔离级别后,线上又出现了并发控制不住的情况又出现了,分析还是分布式锁释放后,另外一个线程立即拿到了锁,进行查询,但是mysql事务提交处理时间(特别开启binlog的情况,是2次确认提交的),如果抢购时需要处理的事务也多,耗时会长一些。

之前分布式锁释放到controller,延迟1秒释放锁,这个不通用,也会出现时间错差的问题。

解决办法,将控制数量的值放到redis中,数据的增加放到分布式锁中,校验以及增加数据都是在分布式锁中处理,这样可以保证锁释放时,控制数量值立即变化。这样就是业务需要修改的代码多一些,还是需要提前做好设计。控制并发还是需要redis分布式锁内处理完数量或者mysql乐观锁。

修改办法:校验处取值redis,分布式锁释放前,增加redis中数量的值

牵扯到预约的逆向,需要控制变量减少数量的业务代码,需要处理多处,。。。

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值