MySQL-两类更新丢失及解决办法
MySQL第一类更新丢失、第二类更新丢失是什么,以及怎么解决。
目录
第一类更新丢失(回滚丢失)
开启事物A | 开启事物B |
查询id = 1的数据age = 500 | |
更新id为1的数据保存age= 100 | |
更新id为1的数据保存age = 200 | 提交事物 |
回滚事物 | |
age恢复500,更新丢失 |
在MySQL数据库,任何隔离级别不允许第一类更新丢失
第二类更新丢失(覆盖丢失)
开启事物A | 开启事物B |
查询id = 1的数据age = 500 | |
更新id为1的数据保存age= 100 | |
更新id为1的数据保存age = 200 | 提交事物 |
提交事物 | age被修改为200,更新丢失 |
如何解决第二类更新丢失
为了解决不可重复读的问题,MySQL提出了可重复读隔离级别
MySQL可重复读默认采用的是一致性非锁定读,也就是快照读。
快照读
快照读的一个问题也就是没有办法获取最新的数据。
开启事物A | 开启事物B |
查询id为1的数据 money = 100 | |
更新id为1的数据设置money = 200 | |
提交事物B | |
查询id为1的数据 money = 100 |
快照读是第二类更新丢失的一个主要原因。
解决快照读
悲观锁
将一致性非锁定读替换为一致性锁定读
这样能够保证读到的数据都是最新的数据,并且会将记录锁住,其他事物如果想要获取锁会阻塞
所以整体业务流程变成:在开启事物后要获取锁,然后根据业务场景不同进行不同操作
开启事物A | 开启事物B |
select * from money where id = 1 for update | |
查到数据 :money = 100 | select * from money where id = 1 for update |
update money set money = money +100 where id = 1; | 阻塞... |
commit | 阻塞... |
查到数据 :money = 200 | |
其他操作.... |
乐观锁
添加version字段,记录每条记录的更新版本,每次更新后版本号加一。
在每次事物开启之前获取行的版本号,在更新的时候带上版本号进行判断。update money set money = money + 100 where id = 1 and version = 查到的版本号
select version from money where id = 1; | select version from money where id = 1; |
获取版本号为0 | 获取版本号为0 |
开启事物A | 开启事物B |
update money set money = money +100 , version = verison +1 where id = 1 and version = 0; | |
更新成功,更新条数为1 | update money set money = money +100 , version = verison +1 where id = 1 and version = 0; |
阻塞... | |
commit | |
更新成功,更新条数为0(因为另一个事物修改了版本号现在版本号为1) | |
rollback; |
更多推荐
所有评论(0)