妄想社成员 发表于 2024-1-10 20:42:37

活字格+mysql,库存数据并发更新时脏读处理方案

本帖最后由 妄想社成员 于 2024-1-10 20:48 编辑

1.先定义脏数据(来源baidu百科):

当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据。
2.定义化用到更新库存的业务:
多个用户同时执行修改库存表中某一商品的库存数量,A用户读取到100,要出库10,新库存数为90,但还未保存更新后的数据,B此时读这一商品库存,为100,出库10,新库存数为90,A更新库存数为90,B更新库存数为90,其中B读到的100数据便为脏数据,这也是并发修改库存数量遇到的问题。


3.mysql5.7 的默认隔离策略为 可重复读

即并发事务可以同时读到数据

4.产生问题的原因:
可重复读策略禁止修改数据,但是可以并发读数据,且该策略在事务运行中生效的机制是遇写入操作时才会锁住对应的行数据,比如(A用户读取到100,要出库10,新库存数为90,但还未保存更新后的数据,B此时读这一商品库存,为100(本应该读到A更新完后的数据:90),出库10,新库存数为90(本应该为80))

5.解决方案:
在事务命令下对可能进行并发读写的库存记录进行一些更新操作,进而在读库存数之前就触发隔离策略的数据锁操作,这样之后读就不会读到脏数据,如下图




可能有说得不对、理解得不对的地方,劳烦佬们指点


phoben 发表于 2024-1-11 20:43:19

可以通过SQL对特定行进行显式隔离,直到事务结束,这样做的好处是可以一次性隔离多行数据,还可以在事务隔离级别的基础上,再施加一个额外的显式锁,可以试试:

给匹配的行施加【排他锁】其他人不能读、不能改
SELECT * FROM xxx WHERE xxxFOR UPDATE;

给匹配的行施加【共享锁】其他人能读,但不能改
SELECT * FROM xxxWHERE xxxLOCK IN SHARE MODE;

可以在事务内一开始先锁上,然后慢慢操作。

马杰 发表于 2024-1-11 13:11:45

没看明白啥意思呢?是说mysql的外联库用服务端命令的默认或者可重复读就可以避免脏读?

妄想社成员 发表于 2024-1-11 13:22:20

马杰 发表于 2024-1-11 13:11
没看明白啥意思呢?是说mysql的外联库用服务端命令的默认或者可重复读就可以避免脏读?

不是,mysql的默认策略可重复读,这个策略锁定数据行的触发机制是遇到数据写入的操作,没遇到之前,是不会起作用的,这就导致并发用户读取库存数读到了一样的数,但这并不是我们想要的,所以通过前置写入操作触发可重复读策略的锁行机制,保证事务的原子性,使得B用户可以在A用户执行完事务之后再读取数据,而不是与A同时读取数据

妄想社成员 发表于 2024-1-11 21:36:52

phoben 发表于 2024-1-11 20:43
可以通过SQL对特定行进行显式隔离,直到事务结束,这样做的好处是可以一次性隔离多行数据,还可以在事务隔 ...

学到了,感谢夏超大佬

小侠米 发表于 2024-1-12 10:12:18

好高深
就是有点疑问,加这么多锁,性能有保障吗

妄想社成员 发表于 2024-1-12 11:06:41

小侠米 发表于 2024-1-12 10:12
好高深
就是有点疑问,加这么多锁,性能有保障吗

这些都是为了应对小概率事件的,这时候保证数据准确优先级更高
页: [1]
查看完整版本: 活字格+mysql,库存数据并发更新时脏读处理方案