mysql为每行数据添加了两个隐藏的字段,一个为保存创建版本号,一个保存删除版本号,版本号根据时间是递增的。
那么我们看下mysql在REPEATABLE READ隔离级别下,MVCC是如何操作的;
我们模拟一张表:
create table tbl(
create_no int,
delete_no int
);
-- 假设事物的版本号 no = 20200525001;
-- insert 操作:创建版本号 = 当前事物版本号;
insert into tbl (icreate_no,delete_no) values (no,null);
-- delete 操作:删除版本号 = 当前事物版本号;
update tbl set delete_no =no;
-- update 操作:
-- 插入一行数据 创建版本号 = 当前事物版本号;
insert into tbl (icreate_no,delete_no) values (no,null);
-- 更细原来行数据 删除版本号 = 当前事物版本号;
update tbl set delete_no =no;
-- select操作:
select
*
from
tbl
where
create_no <= no and delete_no is nll or delete_no > no ;
-- 注释说明
-- 创建版本号<=当前事物版本号 (这样可以确保当前事物读取的行要么是在本事物中创建和修改的要么就是当前事物开始前就存在的行)
-- 并且 删除版本号 is null 或者 删除版本号 > 当前事物版本号 (这样可以确保读到的行是当前事物开始前没有被删除);
有了这两个版本号,使大多数情况下的读操作可以不用加锁,这样设计的可以使读操作简单,性能也很好,并且能保证读到符合的行,不足之处就是每行记录都需要额外的空间存贮空间,需要更多的行坚持工作和一些额外的维护工作。
-- 注意
MVCC只在 REPEATABLE READ 和 REND CONNITTED 两个隔离级别下工作,其他的两个隔离级别下不兼容。 读未提交总是读取最新的数据行,而不符合当前事物版本的数据行。而序列化则会对所有的读取的行都加锁。