加锁失效,非锁之过,加之错也
引言
多个进程或线程同时(或着说在同一段时间内)访问同一资源会产生并发问题。
银行两操作员同时操作同一账户就是典型的例子。比如A、B操作员同时读取一余额为1000元的账户,A操作员为该账户增加100元,B操作员同时为该账户减去 50元,A先提交,B后提交。 最后实际账户余额为1000-50=950元,但本该为1000+100-50=1050。这就是典型的并发问题。
从事零售供应链库存业务,对库存数量操作增减十分频繁,同样存在类似上述银行取款遇到的问题,库存数量操作有误势必给前台销售产生损失影响,因此需要关注对库存数量并发操作下的一致性。
下面通过一个真实的案例分享在并发情况下如何保证库存数量的准确性。
问题是什么-加锁失效
看看下面这段流程和代码,思考会有并发问题吗?

1.加锁前,获取箱子明细数据,此处在锁之外,存在并发脏读问题

2.加锁后,并进行箱子上架分批次回传业务处理

3.加锁后,更新箱子明细上架数量逻辑:已上架数量 = 加锁前的明细数据(脏读) + 报文回传的明细数据 直接进行行更新

原因是什么-加锁的位置不正确

核心的问题原因
有同学这时问了,为啥防重码也没有生效呢?
防重码主要是用作幂等逻辑的,同一个请求多次处理,结果仍然是相同的。
但是这是两次不同的请求,防重码是不同的,因此不能只依赖防重码保证一致性。
解决方案有哪些
1、代码层面:使用锁(如互斥锁、读写锁、分布式锁等)来控制资源的访问,数据获取的全部操作都需要再获取锁后才进行。
将获取箱子明细的代码移动到加锁之后,只有获取到分布式锁,才能执行分批次上架查询和更新(串行化)

对应改造后的代码:

2、数据库层面:实现事务管理,确保数据的一致性;合理设置事务隔离级别,以防止脏读、或者采用乐观锁或悲观锁来处理并发更新,合理设计查询效率,减少锁竞争。
数据库的并发上锁处理和业务代码的上锁是互补的关系
因为无法保证后续业务的调整或其他业务代码的调用能始终保持获取数据的一致性,数据库的并发上锁处理更多是一种兜底保证机制。
乐观锁更新

悲观锁更新

扩展方案
通过以上措施,可以在不同层面有效地防止并发问题,保证系统的数据的一致性。
浙公网安备 33010602011771号