多版本并发控制(Multi-Version Concurrency Control)是MySQL的InnoDB引擎实现隔离级别的一种具体方式。用于实现提交读和可重复读。
它读取的数据库记录,都是当前最新的版本,会对当前读取的数据进行加锁,防止其他事务修改数据。是悲观锁的一种操作。
如下操作都是当前读: select lock in share mode (共享锁)select for update (排他锁)update (排他锁)insert (排他锁)delete (排他锁)串行化事务隔离级别快照读的实现是基于多版本并发控制,即MVCC,既然是多版本,那么快照读读到的数据不一定是当前最新的数据,有可能是之前历史版本的数据。
如下操作是快照读 不加锁的select操作(注:事务级别不是串行化)mvcc用来解决读—写冲突的无锁并发控制,就是为事务分配单向增长的事务id。为每个数据修改保存一个版本,版本与用回滚指针(roll_pointer)相连。
解决问题如下:
并发读-写时:可以做到读操作不阻塞写操作,同时写操作也不会阻塞读操作。解决脏读、不可重复读等事务隔离问题,但不能解决上面的写-写 更新丢失问题。大大提高了并发性通过在每一张表上添加三个隐藏列,来实现不同的版本
trx_id 表示最近一次对本记录行作修改(insert | update)的事务ID。至于delete操作,InnoDB认为是一个update操作,不过会更新一个另外的删除位,将行表示为deleted。并非真正删除。roll_pointer 回滚指针,指向当前记录行 在 undo log 中上一个版本的数据deleted_bit 删除标记位,因Innodb将delete认为是一次update,所以需要一个删除标记位,标记数据是否删除Readview 是mvcc是先多版本控制的关键,通过生成Readview很好的实现了版本之间的隔离,生成Readview时,会将当前活跃的事务id放入Readview中
结构 low_limit_id : 当前活跃事务的最小IDup_limit_id :当前活跃事务的最大IDtrx_ids : 当前活跃事务的ID数组creator_trx_id :当前创建事务的id号(也可能是试图的ID号)一行数据在undo_log中的版本链
大多数对数据的变更操作包括 insert/update/delete,在InnoDB里,undo log分为如下两类: ①insert undo log : 事务对insert新记录时产生的undo log, 只在事务回滚时需要, 并且在事务提交后就可以立即丢弃。②update undo log : 事务对记录进行delete和update操作时产生的undo log,不仅在事务回滚时需要,快照读也需要,只有当数据库所使用的快照中不涉及该日志记录,对应的回滚日志才会被purge线程删除。Purge线程:为了实现InnoDB的MVCC机制,更新或者删除操作都只是设置一下旧记录的deleted_bit,并不真正将旧记录删除。 为了节省磁盘空间,InnoDB有专门的purge线程来清理deleted_bit为true的记录。purge线程自己也维护了一个read view,如果某个记录的deleted_bit为true,并且DB_TRX_ID相对于purge线程的read view可见,那么这条记录一定是可以被安全清除的。
使用Readview和undo_log的版本链,通过比较判断是否可见
用trx_id 与 low_limit_id 比较,trx_id < low_limit_id;说明事务已提交用trx_id 与 up_limit_id 比较,trx_id >= up_limit_id ;说明事务未提交,不可见用 trx_id 分别与low_limit_id、up_limit_id比较;low_limit_id <= trx_id < up_limit_id时;再判断 trx_id 是否在 trx_ids数组中;如果存在,说明事务未提交,不可见;如果不存在说明事务已提交,可见。