MySQL中的锁和MVCC
在学习MySQL中的锁机制相关时搜集了几篇写得非常不错的博客,这里就不再花时间详细介绍,本篇仅做总结和重点部分摘录(摘自:传送门)。推荐先理解下面篇博客(写得很赞): https://www.cnblogs.com/crazylqy/p/7611069.html
概述
InnoDB的MVCC
- 概述: MVCC(Multi-Version Concurrency Control)多版本并发控制,MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,它在不同的数据库引擎中有不同的实现。
MySQL中MVCC只能在Repeatable Read(读可重复读)、Read Committed(读可提交)这两个隔离级别下工作。
- 用途: MVCC实现的是
普通读取不加锁
,并且读写不冲突
,根据28定律,通常大部分为读操作,避免了读操作的加锁可以大大提高性能
。 - 原理:
- MVCC是通过
保存了数据库某个时间的快照
来实现的。也就是说当几个事务开启的时间不同
,可能会出现同一时刻
、不同事务
读取同一张表
的同一行
记录是不一样的。这个机制也是可重复读的实现。
先看一个例子:
在一个与MySQL的连接中启动事务,读取tno为1的教师姓名,结果为tom(还未commit)
再启动第二个连接,将tno为1的教师名改成了jery
begin;
update teacher set tname="jery" where tno=1;
commit;
此时,事务已经提交,我们再次从第一个连接的事务中查询tno为1的教师姓名
结果依然为tom,并没有读取到最新修改的数据jery,原因就在于每个事务读取的都是专有的快照
。
- 在InnoDB引擎的数据库中,每一行记录后都有几个隐藏列来记录信息:
先了解一下两个概念:系统版本号: 每当启动一个事务时,系统版本号会递增。
事务版本号 事务开始时的系统版本号作为该事务的版本号,事务的版本号用于在select操作中与记录的DATA_TRX_ID字段做对比。隐藏列:
DATA_TRX_ID:
记录了某行记录的系统版本号,每当事务commit对该行的修改操作时就会将。
DATA_ROLL_PTR:
记录了此行记录的回滚记录指针,找之前的历史版本就是通过它。
DELETE BIT:
标记此记录是否正在有事务删除它,最后真正的删除操作是在事务commit后。
- 增删改查中的MVCC操作:
select:
①执行select操作时,InnoDB会查找到对应的数据行,并对比DATA_TRX_ID(版本号),要求数据行的版本必须小于等于
事务的版本,如果当前数据行版本大于此事务版本,那么InnoDB会进入undo log中查找。确保当前事务读取的是事务之前存在的,或者是由当前事务创建或修改的行
。 ② InnoDB会查找到对应的数据行后,查看DELETE BIT是否被定义,只允许未定义,或者删除的版本要大于此事务版本号。保证在执行此事务之前还未被删除
。 当且仅当这两个条件都成立才允许返回select结果!
insert:
InnoDB创建新记录,并以当前系统的版本号为新增记录的DATA_TRX_ID,如果需要回滚则丢弃undo log。
delete:
InnoDB寻找到需要删除的记录,将此记录的DELETE BIT设置为系统当前版本号
,若事务回滚则去除DELETE BIT定义的版本号,若事务提交则删除行。
update:
InnoDB寻找到需要更新的行记录,复制了一条新的记录,新记录的版本ID为当前系统版本号,新记录的回滚指针指向原记录,将原记录的删除ID也设置为当前系统版本号。提交后则删除原记录,若回滚则删除复制的记录,并清除原记录的删除ID。
现在分析一下上一个例子:
假设当前tno=1的教师记录的DATA_TRX_ID = 2,那么第一个事务开启时系统版本号假设为3,在第一个事务中执行的查询操作只会读取DATA_TRX_ID <