MVCC全称Mutli Version Concurreny Control,多版本并发控制,也可称之为一致性非锁定读;它通过行的多版本控制方式来读取当前执行时间数据库中的行数据。实质上使用的是快照数据,这样就可以实现不加锁读。MVCC 主要应用于 Read Commited 和 Repeatable read 两个事务隔离级别。
innoDB 向数据库中存储的每行添加三个隐藏字段
1 DB_TRX_ID
事务id
占6 字节,表示这一行数据最后插入或修改的事务id。此外删除在内部也被当作一次更新,在行的特殊位置添加一个删除标记(记录头信息有一个字节存储是否删除的标记)。
2 DB_ROLL_PTR
回滚指针
占7字节,回滚指针指向被写在Rollback segment
中的undoLog记录,在该行数据被更新的时候,undoLog 会记录该行修改前内容到undoLog。
3 DB_ROW_ID
行ID
占7字节,他就项自增主键一样随着插入新数据自增。如果表中不存主键 或者 唯一索引,那么数据库 就会采用DB_ROW_ID
生成聚簇索引。否则DB_ROW_ID
不会出现在索引中。
3.2 undo log
undo log是为回滚而用,具体内容就是copy事务前的数据库内容(行)到undo buffer,在适合的时间把undo buffer中的内容刷新到磁盘。undo buffer与redo buffer一样,也是环形缓冲,但当缓冲满的时候,undo buffer中的内容会也会被刷新到磁盘;与redo log不同的是,磁盘上不存在单独的undo log文件,所有的undo log均存放在主ibd数据文件中(表空间),即使客户端设置了每表一个数据文件也是如此。
undo log 在 Rollback segment
中又被细分为 insert 和 update undo log , insert 类型的undo log 仅仅用于事务回滚,当事务一旦提交,insert undo log 就会被丢弃。update的undo log 被用于 一致性的读和事务回滚,update undo log 的清理 是在 没有事务 需要对这部分数据快照进行一致性读的时候 进行清理。
undo log 的创建
每次对数据进行更新操作时,都会copy 当前数据,保存到undo log 中。并修改 当前行的 回滚指针指向 undo log 中的 旧数据行。
3.3 read_view 判断数据行可见性
在innodb中,创建一个新事务的时候,innodb会将当前系统中的活跃事务列表创建一个副本(read view),副本中保存的是系统当前不应该被本事务看到的其他事务id列表。当用户在这个事务中要读取该行记录的时候,innodb会将该行当前的版本号与该read view进行比较。
具体的算法是(可重复读级别):
假设当前 数据行 事务ID 为 T0 ,read view 中保存的 最老的事务id T_min ,最新的 事务id 为 T_max,当前进行的事务id 为 T_new 。
DB_ROLL_PTR
指针 找到下一个 数据版本,再次进行数据可见性判断。DB_ROLL_PTR
指针 找到下一个 数据版本,再次进行数据可见性判断。3.4 Read Commited ,Repeatable read 数据可见性判断
Read Commited 和 Repeatable read 采用相同的数据可见性判断逻辑。
那么怎么在相同的判断逻辑下 分别 实现 RC 和 RR 级别的?
正是因为Read Commited和 Repeatable read的read view 生成方式和时机不同,导致在不同隔离级别下,read committed 总是读最新一份快照数据,而repeatable read 读事务开始时的行数据版本。