MVCC总结


原理

体上来讲MVCC的实现是基于ReadView版本链以及Undo日志实现的

MVCC就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程,这样可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能;

InnoDB存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏

trx_id:每次一个事务对某条聚簇索引记录进行改动时,都会把该事务的事务id赋值给trx_id隐藏列。

roll_pointer:每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,然后列就相当于一个指,可以通该记录修改前的信息

每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性

ReadView

需要判断一下版本链中的个版本是当前事可见的,readview就是根据规则判断可显示的记录。

max trx id min trx id < trx id < max trx id &&trx id in m ids min trx id < trx id < max trx id trx id not in m ids ??JLx?" width="619" height="253">

如果某个版本的数据对当前事务不可见的话,那么着版本链找到下一个版本的数继续照上面的规则继续进行判断,以此推,若是到了最后一个版本,版本的数据仍当前事不可那么就表明该条记录对该事务完全不可见,查询结果就不会包含该条记录

见问题

是否解决了幻读

会有幻读

select I egtx_isolation I REPEATABLE-READ I row in set, I warning (O. 00 sec) uery OK, O rows affected ( .00 sec) ysql> select * from account where id>2; j id I name I balance 3 Lin 100 4 Yan 100 rows in set (0. 00 sec) 2 6 - mvsal ?u root -p mysql) select 00tx_isolation; "tx_isolation I I REPEATABLE-READ I 1 row in set, I warning (O. sec) mysql> begin; Query OK, O rows affected (O. 00 sec) mysql> insert into account (id, name, balance) value(5. 'Wei' , 100) Query OK, I row affected (O. 00 sec) mysql> comit; Query OK, O rows affected (O. 01 sec) mysql> sql> update account set balance=200 where id=5; ery OK. I row affected (0. 01 sec) ysql> select * from account where id>2; 3 4 5 Lin Yan wei 100 100 200 7" width="611" height="322">

InnoDB存储引擎在 RR 级别下通过 MVCC和 Next-key Lock 来解决幻读问题:

1、执行普通 select,此时会以 MVCC 快照读的方式读取数据 在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读

2、执行 select...for update/lock in share mode、insert、update、delete 等当前读 在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读!InnoDB 使用 Next-key Lock  (opens new window) 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。只要我不让你插入,就不会发生幻读 # 参考