浅析Innodb MVCC机制

MVCC实现原理

Innodb MVCC主要是为Repeatable-Read事务隔离级别做的。在此隔离级别下,A、B客户端所示的数据相互隔离,互相更新不可见。

innodb存储的最基本row中包含一些额外的存储信息 DATA_TRX_ID,DATA_ROLL_PTR,DB_ROW_ID,DELETE BIT

  1. 6字节的DATA_TRX_ID 标记了最新更新这条行记录的transaction id,每处理一个事务,其值自动+1
  2. 7字节的DATA_ROLL_PTR 指向当前记录项的rollback segment的undo log记录,找之前版本的数据就是通过这个指针
  3. 6字节的DB_ROW_ID,当由innodb自动产生聚集索引时,聚集索引包括这个DB_ROW_ID的值,否则聚集索引中不包括这个值.,这个用于索引当中
  4. DELETE BIT位用于标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候

具体的执行过程

begin->用排他锁锁定该行->记录redo log->记录undo log->修改当前行的值,写事务编号,回滚指针指向undo log中的修改前的行

上述过程确切地说是描述了UPDATE的事务过程,其实undo log分insert和update undo log,因为insert时,原始的数据并不存在,所以回滚时把insert undo log丢弃即可,而update undo log则必须遵守上述过程。下面分别以select、delete、 insert、 update语句来说明

SELECT

Innodb检查每行数据,确保他们符合两个标准:

  1. InnoDB只查找版本早于当前事务版本的数据行(也就是数据行的版本必须小于等于事务的版本),这确保当前事务读取的行都是事务之前已经存在的,或者是由当前事务创建或修改的行

  2. 行的删除操作的版本一定是未定义的或者大于当前事务的版本号,确定了当前事务开始之前,行没有被删除

符合了以上两点则返回查询结果。

INSERT

InnoDB为每个新增行记录当前系统版本号作为创建ID。

DELETE

InnoDB为每个删除行的记录当前系统版本号作为行的删除ID。

UPDATE

InnoDB复制了一行。这个新行的版本号使用了系统版本号。它也把系统版本号作为了删除行的版本。

说明:

  • insert操作时 “创建时间”=DB_ROW_ID,这时,“删除时间 ”是未定义的;

  • update时,复制新增行的“创建时间”=DB_ROW_ID,删除时间未定义,旧数据行“创建时间”不变,删除时间=该事务的DB_ROW_ID;

  • delete操作,相应数据行的“创建时间”不变,删除时间=该事务的DB_ROW_ID;

  • select操作对两者都不修改,只读相应的数据

对于MVCC的总结

上述更新前建立undo log,根据各种策略读取时非阻塞就是MVCC,undo log中的行就是MVCC中的多版本,这个可能与我们所理解的MVCC有较大的出入,一般我们认为MVCC有下面几个特点:

  1. 每行数据都存在一个版本,每次数据更新时都更新该版本修改时Copy出当前版本随意修改,各个事务之间无干扰保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)
  2. 就是每行都有版本号,保存时根据版本号决定是否成功,听起来含有乐观锁的味道,而Innodb的实现方式是:
  3. 事务以排他锁的形式修改原始数据
  4. 把修改前的数据存放于undo log,通过回滚指针与主数据关联
  5. 修改成功(commit)啥都不做,失败则恢复undo log中的数据(rollback)

你可能感兴趣的:(数据库问题整理)