Mysql InnoDB存储引擎基于Multi-Version Concurrency Control(MVCC,多版本的并发控制协议)实现。MVCC是通过保存数据在某个时间点的快照来实现的;优点是:读不加锁,读写不冲突。
一 原理
1 实现原理
InnoDB的MVCC可以是通过在每行记录中保存两个隐藏的列来实现的,创建事物id,删除事物id。每开始一个新的事务,系统版本号(可以理解为事务的ID)就会自动递增,事务开始时刻的系统版本号会作为事务的ID。
Innodb的最基本行记录(row)中包含一些额外的存储信息:DATA_TRX_ID,DATA_ROLL_PTR,DB_ROW_ID,DELETE BIT
列名 |
长度 |
备注 |
DATA_TRX_ID |
6字节 |
标记了最新更新这条行记录的transaction id,每处理一个事务,事物值自动+1 |
DATA_ROLL_PTR |
7字节 |
指向当前记录项的rollback segment的undo log记录,找之前版本的数据就是通过这个指针 |
DB_ROW_ID |
6字节 |
innodb自动产生聚集索引时,聚集索引包括这一列,否则聚集索引中不包括这个值。 |
DELETE BIT |
|
位用于标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候 |
2 Select
当隔离级别是REPEATABLE READ时select操作,InnoDB查询时必须保证每行数据符合两个条件:
InnoDB只查找版本号必须小于等于事务版本的数据行。这确保当前事务读取的行都是事务之前已经存在的,或者是由当前事务创建或修改的行。
行的删除操作的版本一定是未定义的或者大于当前事务的版本号,确定了当前事务开始之前,行没有被删除。
3 实现
MVCC有下面几个特点(看起来有点乐观锁的味道):
a、每行数据都存在一个版本。
b、每次数据更新时都更新该版本 修改时Copy出当前版本随意修改,个事务之间无干扰。
c、保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)。
Innodb的MVCC实现方式如下:
a、事务以排他锁的形式修改原始数据,
b、把修改前的数据存放于undo log,通过回滚指针与主数据关联
c、修改成功(commit)啥都不做,失败则恢复undo log中的数据(rollback)
二 MVCC示例
接下来讲述在REPEATABLE READ隔离级别下,MVCC具体是如何操作的。
1 表结构
假设存在表user,结构如下:
加上DATA_TRX_ID、DATA_ROLL_PTR、DB_ROW_ID后的结果如下:
2 insert
假设当前事务id=1,插入一条记录,sql如下:
insert into user value("a1");
结果数据如下:
3 update
假设原始数据如下:
假设当前事务id=2,更新sql如下:
update user set name="a2" where id =1;
更新时数据变动如下:
事务执行过程:
事务开始.
记录name=a1 到undo log.
修改name=a2、DATA_ROOL_PTR=UNDO LOG的记录id
记录name=a2 到redo log.
将redo log、undo写入磁盘。
事务提交
说明:如果undo log一直不删除,则会通过当前记录的回滚指针回溯到该行创建时的初始内容,所幸的时在Innodb中存在purge线程,它会查询那些比现在最老的活动事务还早的undo log,并删除它们,从而保证undo log文件不至于无限增长。
4Â Â delete
假设原始数据如下:
假设当前事务id=3,delete sql如下:
delete from user where id =1
事务执行过程:
事务开始.
记录原数据到undo log.
修改记录的DELETE BIT=1、DATA_ROOL_PTR=UNDO LOG的记录id
记录删除操作到redo log.
将redo log、undo写入磁盘。
事务提交