一文浅析MySQL怎么解决幻读问题

文 / @WordPress主题

如何解决MySQL的幻读问题?

幻读问题在MySQL的事务隔离级别中是一种经典问题,很多面试题也常常涉及到这个问题。在MySQL中,其事务特性(ACID)包括原子性、隔离性、一致性和持久性,隔离级别包括读取未提交(READ UNCOMMITTED)、读取已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和可串行化(SERIALIZABLE)四种。

不同的隔离级别可能导致不同的问题,比如READ UNCOMMITTED可能会出现脏读、不可重复读和幻读问题,READ COMMITTED则可能出现不可重复读和幻读问题,而REPEATABLE READ则可能会出现幻读问题。

针对这些问题,MySQL的InnoDB存储引擎默认支持的隔离级别是REPEATABLE READ。尽管这个隔离级别下依然存在幻读问题,但是MySQL的InnoDB存储引擎已经解决了幻读问题的发生。

1. 行格式

在了解MySQL如何解决幻读问题之前,先需要了解行格式。行格式是指在表中行记录所使用的存储格式,InnoDB存储引擎共支持4种不同类型的行格式:compact、redundant、dynamic、compress。

无论使用哪种行格式,每条记录都被分为记录的额外信息和记录的真实数据两部分。记录的额外信息包括变长字段长度列表、NULL值列表和记录头信息,而记录的真实数据则包括自定义的列和MySQL为每个记录添加的默认列,也称为隐藏列。默认列包括行ID、事务ID和回滚指针等。

2. MVCC详解

MVCC(多版本并发控制)是MySQL InnoDB存储引擎解决幻读问题的核心机制。

2.1 版本链

每次对一条记录进行更新操作时,都会记录一条undo日志。该记录每个版本都包含事务ID、回滚指针和新数据等信息,并且通过一个roll_pointer属性链接起来形成一个版本链。

2.2 ReadView

针对READ COMMITTED和REPEATABLE READ隔离级别,其核心问题是版本链中哪些版本是可见的。为了解决这个问题,MySQL提出了ReadView概念。

ReadView包含四个核心概念:m_ids、min_trx_id、max_trx_id和creator_trx_id。有了ReadView,MySQL可以通过判断访问记录的某个版本是否可见来实现幻读问题的解决。具体地,在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:

1. 如果被访问的版本的事务ID等于creator_trx_id,则说明当前事务正在访问自己修改的记录,所以该版本可见;
2. 如果被访问的版本的事务ID小于min_trx_id,则说明在创建ReadView的时候,该事务已经提交,该版本对当前事务可读;
3. 如果被访问的版本的事务ID大于或等于max_trx_id,则说明该版本记录的事务是在创建ReadView之后开启的,所以该版本不能被当前事务可读;
4. 如果被访问的版本的事务ID是m_ids集合中的,则说明生成ReadView的时候,该事务还未提交,该版本不能被访问;
5. 如果不在m_ids集合中,则说明生成该版本记录的事务已经被提交,此时该版本可以被访问。

3. 总结

基于MVCC,在REPEATABLE READ隔离级别下,MySQL很好地解决了幻读问题。但是,如果使用当前读,MySQL会使用间隙锁来保证不会出现幻读。

以上就是MySQL如何解决幻读问题的简要分析。需要指出的是,本篇文章着重介绍了相关概念和技术,但是由于涉及的内容较为复杂,因此建议结合实际业务场景进行学习和实践。

添加UTHEME为好友
扫码添加UTHEME微信为好友
· 分享WordPress相关技术文章,主题上新与优惠动态早知道。
· 微信端最大WordPress社群,限时免费入群。