MVCC:
多版本并发控制 指的就是在使用RC和RR隔离级别的事务,在执行普通select操作时,访问记录版本链的过程;使不同事务的读写、写读操作并发执行,提高系统性能;
用于实现提交读和可重复读
多版本并发控制简单的说就是当前事务只能看见已经提交的数据记录,看不到正在修改的数据记录。所以我们只要弄清楚那些事务对于当前事务是已经提交的,那些事务对于当前事务是活跃的。
Serializable (序列化) 数据库事务的最高隔离级别。在此级别下,事务串行执行。可以避免脏读、不可重复读、幻读等读现象。但是效率低下,耗费数据库性能,不推荐使用。
事务的三种隔离级别
READ UNCOMMITTED (RU)——直接读取记录的最新版本:可以读到未提交事务修改过的记录
READ COMMITTED (RC)—— 每次读取数据前都生成一个ReadView
REPEATABLE READ (RR)—— 在第一次读取数据时生成一个ReadView
RC和RR隔离级别事务:需要用到版本链概念,核心问题是如何判断版本链中哪个版本是当前事务可见的?
RC、RR 两种隔离级别的事务在执行普通的读操作时,通过访问版本链的方法,使得事务间的读写操作得以并发执行,从而提升系统性能。
ReadView(事务进行快照读操作的时候生产的读视图 一致性读视图):
用于支持读提交和可重复读隔离级别的实现,作用是执行期间判断版本链中的哪个版本是当前事务可见的
trx_id:每次对某条记录进行改动时,对会把对应的事务id赋值给trx_id隐藏列;
m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表 记录有哪些事务在mysql里还没有提交。
min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
creator_trx_id:表示生成该ReadView的事务的事务id。
(可见)如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
(可见)如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
(不可见)如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
(不可见)如果trx_id in m_ids,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问。
(可见)如果trx_id not in m_ids,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
如果某个版本的数据对当前事务不可见,那就顺着版本链找到下一个版本的数据,并继续执行上面的步骤来判断记录的可见性,以此类推,直到版本链中的最后一个版本。
undo log存储机制(版本链):
在每次更新该记录后,都会将旧值放到一条undo日志中。随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一条链表,这个链表就称之为版本链。
DB_TRX_ID:事务 ID,是根据事务产生时间顺序自动递增的,是独一无二的。如果某个事务执行过程中对该记录执行了增、删、改操作,那么InnoDB存储引擎就会记录下该条事务的 id。
DB_ROLL_PTR:回滚指针,本质上就是一个指向记录对应的undo log的一个指针,InnoDB 通过这个指针找到之前版本的数据
DB_ROW_ID:主键,如果有自定义主键,那么该值就是主键;如果没有主键,那么就会使用定义的第一个唯一索引;如果没有唯一索引,那么就会默认生成一个隐藏列作为主键。
innodb事务日志包括redo log和undo log。redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。
redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。
Insert undo log :insert生成的日志,仅在事务回滚中需要,并且可以在事务提交后立即丢弃。
Update undo log:update/delete生成的日志,除了用于事务回滚,还用于一致性读取,只有不存在innodb为其分配快照的事务之后才能丢弃它们,在一致读取中可能需要update undo log中的信息来构建数据库行的早期版本。
MVCC工作流程
1 查询主键索引
生成Read View读视图
通过主键查找记录,根据记录里的DB_TRX_ID与Read View读视图进行可见性判断
配合DB_ROLL_PTR回滚指针和undo log来找到当前事务可见的数据记录
解决问题:
脏读 不可重复读 幻读
总结:
Mysql实现MVCC机制,就是基于undo log多版本链表+ReadView机制来实现的。默认的RR隔离级别,也是基于这套机制来实现的,处理避免脏读、不可重复读的问题,还能解决幻读的问题,因此我们一般都默认为RR隔离级别就好了