找回密码
 立即注册

QQ登录

只需一步,快速开始

妄想社成员 活字格认证

高级会员

72

主题

389

帖子

1777

积分

高级会员

积分
1777

时代开发者征文活动活字格认证圣诞拼拼乐

QQ
妄想社成员 活字格认证
高级会员   /  发表于:2024-1-10 20:42  /   查看:1621  /  回复:6
本帖最后由 妄想社成员 于 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 的默认隔离策略为 可重复读
image.png689930114.png
即并发事务可以同时读到数据

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

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

image.png95893858.png


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


6 个回复

倒序浏览
phoben讲师达人认证 悬赏达人认证 活字格认证
论坛元老   /  发表于:2024-1-11 20:43:19
推荐
可以通过SQL对特定行进行显式隔离,直到事务结束,这样做的好处是可以一次性隔离多行数据,还可以在事务隔离级别的基础上,再施加一个额外的显式锁,可以试试:

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

给匹配的行施加【共享锁】其他人能读,但不能改
SELECT * FROM xxx  WHERE xxx  LOCK 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
5#
phoben 发表于 2024-1-11 20:43
可以通过SQL对特定行进行显式隔离,直到事务结束,这样做的好处是可以一次性隔离多行数据,还可以在事务隔 ...

学到了,感谢夏超大佬
回复 使用道具 举报
小侠米
论坛元老   /  发表于:2024-1-12 10:12:18
6#
好高深
就是有点疑问,加这么多锁,性能有保障吗
回复 使用道具 举报
妄想社成员活字格认证
高级会员   /  发表于:2024-1-12 11:06:41
7#
小侠米 发表于 2024-1-12 10:12
好高深
就是有点疑问,加这么多锁,性能有保障吗

这些都是为了应对小概率事件的,这时候保证数据准确优先级更高
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 立即注册
返回顶部