InnoDB MVCC InnoDB 的 MVCC, 其实是通过 undo log 来实现的, 可以理解为是通过在每行记录后面保存两个隐藏的列来实现的, 分别保存了这个行的创建时间, 一个保存的是行的删除时间. 这里存储的并不是实际的时间值, 而是系统版本号(可以理解为事物的 Id), 每开始一个新的事物, 系统版本号就会自动递增, 事物开始时刻的版本号会作为事物 Id. 对应在数据中的表如下(后面两列是隐藏列, 我们通过查询语句并看不到)
SELECT InnoDB 会根据以下两个条件检查每行记录: 1. InnoDB 只会查找版本早于当前事务版本的数据行(也就是 行 的系统版本号小于或等于事物的系统版本号), 这样可以确保事物读取的行, 要么是在事物开始前已经存在的, 要么是事物自身插入或者修改过的. 2. 行 的删除版本要么未定义, 要么大于当前事务版本号( 这可以确保事物读取到的行, 在事物开始之前未被删除) 只有条件 1, 2 同时满足的记录, 才能返回作为查询结果 DELETE InnoDB 会为删除的每一行保存当前系统的版本号( 事物ID) 作为删除标识 看下面的具体例子分析: 第二个事物, Id为 2:
start transaction; select * from yang; select * from yang; commit;
假设1: 假设在执行这个事物 Id 为2的过程中, 刚执行到 (1), 这时, 有另一个事物 Id 为 3 往这个表里插入了一条数据; 这个事物 Id 为 3
start transaction; insert into yang values(NULL,'tian'); commit;
这时表中的数据如下:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
1 | yang | 1 | undefined |
2 | long | 1 | undefined |
3 | fei | 1 | undefined |
4 | tian | 3 |
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
1 | yang | 1 | undefined |
2 | long | 1 | undefined |
3 | fei | 1 | undefined |
start transaction; delete from yang where id=1; commit;
此时数据库中的表如下
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
1 | yang | 1 | 4 |
2 | long | 1 | undefined |
3 | fei | 1 | undefined |
4 | tian | 3 | undefined |
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
1 | yang | 1 | 4 |
2 | long | 1 | undefined |
3 | fei | 1 | undefined |
start transaction; update yang set name='Long' where id=2; commit;
根据 UPDATE 的更新原则: 会生成新的一行, 并在原来要修改的列的删除时间上添加本事物 ID, 得到表如下:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
1 | yang | 1 | 4 |
2 | long | 1 | 5 |
3 | fei | 1 | undefined |
4 | tian | 3 | undefined |
2 | Long | 5 | undefined |
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
1 | yang | 1 | 4 |
2 | long | 1 | 5 |
3 | fei | 1 | undefined |