本文主要讲解MySQL如何使用MVCC解决脏读、不可重复读和幻读问题相关内容,我们一起来学习下!

并发情况下,读操作可能存在脏读、不可重复读和幻读的问题。可以通过MVCC(Multi-Version Concurrency Control, 多版本并发控制)机制解决这些问题。

一、什么是脏读(Dirty Read)

一个事务读取了已被另一个事务修改,但尚未提交的数据(脏数据)。

二、什么是不可重复读(Nonrepeate Read)

在同一个事务中,同一个查询在时刻1读取某一行,在时刻2重读取这一行数据的时候,发现这一行的数据已经发生修改,可能被更新了,也可能被删除了。

三、什么是幻读(Phantom Read)

在同一事务中,当同一查询多次执行的时候,由于其他插入操作的事务提交,会导致每次返回不同的结果集。

SQL标准定义了四个隔离级别:

隔离级别描述脏读不可重复读幻读
Read Uncommitted 读未提交所有事务都可以看到其他未提交事务的执行结果,事务中的修改,即使没有提交,对其他事务也是可见的。可能可能可能
Read Committed 读已提交一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。不可能可能可能
Repeatable Read 可重复读同一个事务,在多次读取同一行数据的时候,得到的是同样的结果。不可能不可能可能
Serializable 可串行化强制事务排序,强制事务串行执行,使之不可能相互冲突。不可能不可能不可能

InnoDB存储引擎默认的隔离级别是可重复读。

-- 查询当前会话的事务隔离级别 SELECT @@transaction_isolation; -- 查询系统的事务隔离级别 SELECT @@global.transaction_isolation; 
mysql> SELECT @@transaction_isolation; +-------------------------+ | @@transaction_isolation | +-------------------------+ | REPEATABLE-READ | +-------------------------+ 1 row in set (0.00 sec) mysql> SELECT @@global.transaction_isolation; +--------------------------------+ | @@global.transaction_isolation | +--------------------------------+ | REPEATABLE-READ | +--------------------------------+ 1 row in set (0.00 sec) 

接下来看一下MVCC是如何解决脏读、不可重复读、幻读的问题的。MVCC多版本并发控制,能够实现在同一时刻,不同事务中读取到的数据是不同的(即多版本)。

MVCC通过隐藏列和undo log实现ReadView,通过ReadView来判断不同事务要使用哪个版本的数据。

一、如何解决脏读问题

事务A在查询余额前会生成ReadView,事务B此时还未提交,对数据的修改对ReadView不可见,所以事务A中读取到的是修改前的数据。

二、如何解决不可重复读问题

事务A在第1次查询余额前会生成ReadView,事务B的修改对ReadView是不可见的,再次查询时通过判断事务B已经提交的修改对事务A仍然是不可见的,就通过undo log查询修改前的版本的数据。

三、如何解决幻读问题

解决幻读的问题和解决不可重复读的问题类似。

使用MVCC避免脏读、不可重复读、幻读,保证了隔离性,MVCC中使用的是非加锁读,也称作快照读。

另外还可以使用加锁读:

START TRANSACTION; -- 共享锁读取 SELECT * FROM users WHERE id=1 LOCK IN SHARE MODE; -- 排他锁读取 SELECT * FROM users WHERE id=1 FOR UPDATE; UPDATE users SET name="王小明" WHERE id=1; COMMIT; 

SELECT ... LOCK IN SHARE MODE;用于在查询数据时获取共享锁,防止其他事务对数据进行写操作,但允许事务对数据进行读操作。

SELECT ... FOR UPDATE;用于在查询数据时获取排他锁,防止其他事务对数据进行读写操作。

总结

以上就是MySQL如何使用MVCC解决脏读、不可重复读和幻读问题的全部内容,希望对你有帮助,欢迎持续关注潘子夜个人博客(www.frpkj.com),学习愉快哦!