MVCC机制
使用MVCC(Multi-Version Concurrency Control,多版本的并发控制协议)机制来实现可重复读(REPEATABLE READ)的隔离级别
MVCC最大的优点是读不加锁,因此读写不冲突,并发性能好。InnoDB实现MVCC,是通过保存数据在某个时间点的快照来实现的,多个版本的数据可以共存,主要是依靠数据的四个隐藏列(也可以称之为标记位)和undo log。其中数据的隐藏列包括了隐含的自增主键(DB_ROW_ID),最近更改的事务ID(DB_TRX_ID)、undo log的指针(DB_ROLL_PTR)、索引删除标记(FLAG数据被删除时,并不是立即删除,而是打上删除标记,进行异步删除);在进行数据修改时,当前记录会进行加锁,把修改前的数据放入undo log中,通过undo log的指针与数据进行关联,如果修改失败,则恢复undo log中的数据
事务对一条数据进行修改时,undolog日志会生成一条记录版本的链表,链首是最新的旧记录,链尾是最早的旧记录
事务隔离级别READ COMMITTED时,对于快照数据,总是读取被锁定行的最新一份快照数据
事务隔离级别REPEATABLE READ时,对于快照数据,总是读取事务开始时的行数据版本
ReadView
ReadView包含四个字段
- m_ids 当前活跃的事务id集合
- min_trx_id 最小活跃事务id
- max_trx_id 最大事务id,已创建的最大事务id
- creator_trx_id 快照读创建者的事务id
在READ UNCOMMITED的隔离级别下,select都是当前读;而在SERIALIZABLE级别下,是通过表锁来限制数据,所以MVCC是在READ COMMITED和REPEATABLE READ的级别下才会生效
在READ COMMITED级别下,每一次select都会重新将系统中所有活跃事务拷贝到每一个列表中生成ReadView。
在REPEATABLE READ级别下,每个事务read时,会将当前系统中所有活跃事务拷贝到一个列表中生成ReadView,后续所有select都复用该ReadView
当执行查询sql时会生成一致性视图ReadView,它是由执行查询时所有未提交事务id数组(m_ids)和已创建的最大事务id(max_trx_id)组成,查询的数据结果需要跟ReadView做对比从而得到快照结果
简单总结
可能看着有点懵,简单说下就是存了两个事务id,一个是创建事务id,一个是删除事务id。在一个事务内查询时,mysql只会查询创建事务id小于当前事务id的行,这样可以确保这个行是在当前事务中或在之前事务中创建的;一个行的删除事务id要么没定义,要么比当前事务id大,满足这两个条件才可以查询出来
对于修改数据,实际是新增一条数据
事务id全局唯一递增
现在事务1插入了一条数据 张三,创建事务id就是1
数据 | 创建事务id | 删除事务id |
---|---|---|
张三 | 1 |
事务2就可以查到 张三,相当于执行的是 select * from table where name = '张三' and create_tra_id <= 2
此时事务3,将张三删除,删除事务id就是3
数据 | 创建事务id | 删除事务id |
---|---|---|
张三 | 1 | 3 |
那么事务2还可以查询到张三这条数据吗?可以查到的,相当于执行的是 select * from table where name = '张三' and create_tra_id <= 2 and delete_tra_id >2