多版本并发控制:读取数据时通过一种类似快照的方式将数据保存下来,这样读锁和写锁就不冲突了,不同的事务session会看到自己特定版本的数据,版本链。
MVCC只在读已提交和可重复读两个隔离级别下工作,因为读未提交总会读取最新的数据,可序化则是会对所有读取的行都加锁。
聚簇索引记录中有两个必要的隐藏列:
trx_id(事务id):用来存储每次对某条聚簇索引记录进行修改的时候的事务id。
roll_pointer(回滚指针):每次对那条聚簇索引记录有修改的时候,都会把老版本写入undo日志中,roll_pointer存储了上个版本的位置指针,可以通过它来获取到上一个版本的记录信息,不过插入是没有这个记录的。
读已提交和可重复读的区别在于它们生成ReadView的策略不同。
ReadView:开始事务时会创建ReadView,它是一个用来维护当前活动(未提交)的事务id的一个有序的数组(从小到大)。
事务需要访问数据时,先获取数据中最大的事务id,对比ReadView:
如果事务id要比ReadView里的小,在左边,说明该事务已被提交了,就可以访问。
如果事务id要比ReadView里的大,在右边,说明该事务还未提交,不可以直接访问,需要获取数据的roll_pointer,获取上一版本的记录,再重新比较,如果通过则将上一版本的记录作为快照,不通过就继续比较。
读已提交下的事务,每次查询的开始都会生成一个独立的ReadView,所以这也导致了读已提交会出现幻读;
可重复读下的事务,则是在第一次读时就生成一个ReadView,之后查询都复用这个ReadView。
这就是MySQL的MVCC,通过版本链,实现多版本,可并发读-写,写-读。通过ReadView生成策略的不同实现不同的隔离级别。
网友评论