MySQL 高频面试题解析 第02期:当前读和快照读的区别 | 您所在的位置:网站首页 › 镜像的英文怎么读 › MySQL 高频面试题解析 第02期:当前读和快照读的区别 |
作者简介 无为,多年 MySQL DBA 工作经验,现就职于某知名互联网公司,对 MySQL、 Redis、PostgrepSQL 等主流数据库有一定了解,拥有丰富的一线运维经验。 涉及到 MySQL 的面试时,是不是经常会被问到当前读和快照读的区别? 本节内容就来聊聊这个话题,首先从快照读开始: 1 普通读1.1 定义普通读(也称快照读,英文名:Consistent Read),就是单纯的 SELECT 语句,不包括下面这两类语句: 代码语言:javascript复制SELECT ... FOR UPDATE SELECT ... LOCK IN SHARE MODE普通读的执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁。 小贴士 对于 SERIALIZABLE 隔离级别来说,如果 autocommit 系统变量被设置为OFF,那普通读的语句会转变为锁定读,和在普通的 SELECT 语句后边加 LOCK IN SHARE MODE 达成的效果一样。 1.2 实现方式普通读是通过 undo log + MVCC 来实现的,具体我们再仔细聊聊: 下图右侧黄色部分是数据:一行数据记录,主键 ID 是 10,object = 'Goland' ,被 update 更新为 object = 'Python' 。 事务会先使用“排他锁”锁定该行,将该行当前的值复制到 undo log 中,然后再真正地修改当前行的值,最后填写事务的 DB_TRX_ID ,使用回滚指针 DB_ROLL_PTR 指向 undo log 中修改前的行。 这里解释一下 DB_TRX_ID 和 DB_ROLL_PTR 所代表的含义: DB_TRX_ID : 6 字节 DB_TRX_ID 字段,表示最后更新的事务 id ( update , delete , insert ) 。此外,删除在内部被视为更新,其中行中的特殊位被设置为将其标记为已软删除。DB_ROLL_PTR : 7 字节回滚指针,指向前一个版本的 undo log 记录,组成 undo 链表。如果更新了行,则撤消日志记录包含在更新行之前重建行内容所需的信息。小贴士 insert undo log 只在事务回滚时需要, 事务提交就可以删掉了。update undo log 包括 update 和 delete , 回滚和快照读都需要。 2 当前读聊完快照读,再聊聊当前读(也称锁定读,Locking Read)。 2.1 定义当前读,读取的是最新版本,并且需要先获取对应记录的锁,如以下这些 SQL 类型: 代码语言:javascript复制select ... lock in share mode 、 select ... for update、 update 、delete 、insert当然,获取什么类型的锁取决于当前事务的隔离级别、语句的执行计划、查询条件等因素。例如,要 update 一条记录,在事务执行过程中,如果不加锁,那么另一个事务可以 delete 这条数据并且能成功 commit ,就会产生冲突了。所以 update 的时候肯定要是当前读,得到最新的信息并且锁定相应的记录。 2.2 实现方式当前读是通过 next-key 锁(行记录锁+间隙锁)来是实现的。 这里补充下行锁的 3 种算法: 行锁(Record Lock):锁直接加在索引记录上面。 间隙锁(Gap Lock):是 Innodb 为了解决幻读问题时引入的锁机制,所以只有在 Read Repeatable 、Serializable 隔离级别才有。 Next-Key Lock :Record Lock + Gap Lock,锁定一个范围并且锁定记录本身 。 下面通过一个例子来说明当前读的实现方式,例如下面这条 SQL: 代码语言:javascript复制delete from T where age = 7;进行下面的实验: 测试可知 delete from T where age = 7; 语句在 age 上的加锁区间为 (4,10) ,图解如下: |
CopyRight 2018-2019 实验室设备网 版权所有 |