💟这里是CS大白话专场,让枯燥的学习变得有趣!
💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话!
💟好记性不如烂键盘,自己总结不如收藏别人!
💌 在讲解 MVCC 之前先来看一下 MySQL 中事务的四种隔离级别:
🍠 读未提交:一个事务可以读到另一个事务未提交的数据。
🍠 读已提交(RC):Oracle 默认,如果一个事务还没有提交,其他事务不能读到该数据。
🍠 可重复读(RR):MySQL 默认,事务A在读到一条数据之后,事务B对该数据进行了修改并提交,事务A再读该数据还是原来的内容,这就需要 MVCC 来实现。
🍠 可串行化:读写加锁。
💌 快照读(一致性读):使用快照信息显示基于某个时间点的查询结果,而不考虑与此同时运行的其它事务所执行的修改。(select * from XXX)
🍠 在 RC 中,每次读取都会重新生成一个快照,总是读取行的最新版本,因此事务中每次 select 也可以看到其它已提交事务所做的修改。
🍠 在 RR 中,快照会在事务中第一次查询语句执行时生成,只有在本事务中对数据进行更改才会更新快照,但会产生幻读。如果在本事务中已经执行了一次 select,其它事务执行了更改数据的操作并已提交,在本事务再次 select 时看不到其它事务所做的更改。
P.S. 当前读:insert、update、delete、select...for update 等。
💌 脏读、不可重复读、幻读的区别:
🍠 脏读:读取了未提交事务的数据(读取阶段,事务进行了回滚等)。
🍠 不可重复读:同一个事务先后两次查询的数据不一致,可能两次查询之间另一个事务执行了更新的操作并已提交。
🍠 幻读:在同一个事务当中先后两次查询结果的总数不一致(插入阶段)。
💌 接下来我们就仔细研究下 MVCC 如何实现 RR 的:
我们知道 MySQL 的三大日志:undo log、redo log、bin log,涉及到回滚的就是 undo log,主要保存了数据的基本信息:
此外,还包含两个隐藏字段 trx_id 和 roll_pointer。
🍠 trx_id :当前这个事务的 id,递增。
🍠 roll_pointer:一个指针,指向上一个版本的 undo log,形成版本链。
💌 基于 undo log 版本链实现 ReadView 机制,它是快照读提取数据的依据:
- m_ids:当前活跃的事务 id 集合。
- min_trx_id:m_ids 里最小事务 id。
- max_trx_id:下一个要生成的事务 id。
- creator_trx_id:ReadView 创建者的事务 id。
根据 ReadView 在版本链中提取满足条件的数据:
🍠 判断当前事务 trx_id 是否等于 creator_trx_id,等于则可以访问(update 之后立即 select)。
🍠 判断 trx_id 是否小于 min_trx_id,小于则已提交,可访问。
🍠 判断 trx_id 是否大于 max_trx_id,大于则是当前 ReadView 生成后产生的,不可访问。
🍠 在二者之间,若不在 m_ids 中则已提交,可访问。
💌 由此 MVCC 可实现可重复读~~