什么是 Mysql 的脏读/ [不] 可重复读/幻读
-- 以下所有内容都基于 InnoDB 存储引擎
1. 各种读
脏读: 事务a读到了其他事务未提交的数据即为脏读
可重复读: 事务a两次读取同一条数据读取到了不同值即为不可重复读,反之即为可重复读(此为快照读,基于mvvc 多版本控制实现)
幻读:(读到其他新增,或者原来有没了,也就是读到了新增和删除【区别于可重复读】)
1. 事务a读取某一个范围的数据(比如 1<userid<5 查询客户的交易记录),第二次读取同样范围的数据,记录数发生变化(增多或减少) 即为幻读(该情况通过mvvc解决)
2. 两次或多次查询都不变(读取某一个范围的数据比如 1<userid<5 查询客户的交易记录),但是如果事务a中有对数据进行更新,再次查询时记录数发生变化(其他事务对该数据范围的数据更新过或者新增过) 也为幻读
第二点发生的原因是: select 读取的数据的方式是快照读, update 读取的数据方式是当前读,即其他事务更新/新增/删除的数据都会被读取到并进行了更新
【更新】这种情况不属于幻读,因为事务a中有更新,更新会使用当前读,也就是读取最新的数据,所以肯定会有其他事务中新增的数据或更新的数据
2. mysql 数据库四种隔离级别:
Read Uncommitted(未提交读) 存在脏读,重复读,幻读
Read Committed(提交读) 不存在脏读,存在不可重复读,幻读
Repeatable Read(可重复读) 不存在脏读,存在可重复读,不存在幻读
Serializable(可串行化) 不存在脏读,存在可重复读,不存在幻读
3. mvvc (快照读基于该机制实现)
MVCC多版本并发控制 实现,(Multi-Version Concurrency Control) 是MySQL中基于乐观锁理论实现隔离级别的方式,增加版本号不加锁
mvvc 对数据的处理: 增加两列 行版本号/行删除标识
新增:新增一条记录,行版本号设置为当前事务号
更新:新增一条记录,行版本号设置为当前事务号,将原数据行删除标识号设置为当前事务号
删除:更新数据的行删除标识号为当前事务号
查询:查找数据行版本号早于当前事务版本号的数据行记录;查找删除版本号要么为NULL,要么大于当前事务版本号的记录
3.1快照读与当前读
读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。
快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
1、SELECT LOCK IN SHARE MODE
2、SELECT FOR UPDATE
3、DELETE\UPDATE\INSERT INTO\REPLACE INTO
4. 总结:
1. mysql通过mvvc机制(也就是快照读与当前读)解决数据库的脏读,不可重复读;
2. 幻读是通过mvvc和 next-key解决的
3. 不同的隔离级别实现了不同的“读”;
参考:
https://blog.csdn.net/sanyuesan0000/article/details/90235335
https://www.jianshu.com/p/0ce1a194ed7c
https://www.cnblogs.com/gaogao67/p/10410888.html
https://blog.csdn.net/Saintyyu/article/details/91269087 (关于锁)
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html(官方,关于锁)

浙公网安备 33010602011771号