在这篇文章中介绍了一致性非锁定读和快照读的概念。快照数据其实就是当前行数据之前的历史版本,每行记录可能有多个版本。一个行记录可能有不止一个快照数据,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control, MVCC)
MVCC只在读已提交READ-COMMITTED(读取已提交)和REPEATABLE-READ(可重复读)这两种事务隔离级别下才有效,是数据库引擎(InnoDB)层面实现的,用来处理读写冲突的手段(不用加锁),提高访问性能。
MVCC是怎么实现的呢,靠的是undo log和read view实现的
每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID字段
6个字节,最近修改/插入这条数据的事务ID:记录创建这条记录/最后一次修改该记录的事务ID。删除也被视为更新,会有一位特殊的标记位来标记这条数据为已被删除
7个字节,回滚指针:指向这条记录的上一个版本(存储于rollback segment里)
6个字节,隐含的自增ID(隐藏主键):如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引
undo log主要分为两种:
事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除
比如一个有个事务插入persion表插入了一条新记录,记录如下,name为Jerry, age为24岁,隐式主键是1,事务ID和回滚指针,我们假设为NULL
现在来了一个事务1对该记录的name做出了修改,改为Tom
又来了个事务2修改person表的同一个记录,将age修改为30岁
不同事务或者相同事务的对同一记录的修改,会导致该记录的undo log成为一条记录版本线性表,既链表,undo log的链首就是最新的旧记录,链尾就是最早的旧记录
有了上面undo log形成的版本链还不够,我们还需要判断版本链中的哪个版本是是当前事务可见的,因此有了一致性视图的概念。其中有四个属性比较重要
版本链中的当前版本是否可以被当前事务可见的要根据这四个属性按照以下几种情况来判断
MySQL源码:
m_up_limit_id = min_trx_id
m_low_limit_id = max_trx_id
如果当前版本不可见的话,那么需要从版本链中继续寻找符合要求的版本,然后读出数据。具体例子可参见这里。