什么是 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(官方,关于锁)

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-07-14 14:07  菜牙caiya  阅读(710)  评论(0)    收藏  举报