文章目录
0 前言
需要的前置知识:
- 事务
- 读写并发一致性
- 隔离级别
1 基本概念
1.1 MVCC介绍
- MVCC是一种用来解决读写冲突的无锁并发控制。
- MVCC和锁机制是MySQL数据库的InnoDB引擎实现事务隔离级别的手段。
- MVCC主要是针对REPEATABLE READ和READ COMMITTED两个隔离级别。
1.2 MVCC的作用
- 与锁不同,MVCC的快照读并不加速(乐观锁的一种实现),因此开销更低。
- 在并发读写数据库时,可以做到读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。
2 版本号和undo log
2.1 版本号
- 系统版本号(SYS_ID):每开始一个新的事务,系统版本号自动递增。
- 事务版本号(TRX_ID):事务开始时的系统版本号
2.2 undo log
2.2.1 隐藏字段
在数据库创建的时候,InnoDB会为每一行增加三个隐藏字段:
- 隐藏主键(DB_ROW_ID):如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。
- 最近修改/插入事务ID(DB_TRX_ID):记录创建这条记录/最后一次修改该记录的事务ID
- 回滚指针(DB_ROLL_PTR):指向这条记录的上一个版本
2.2.2 undo log版本链
当一行数据被多个事务进行修改,每个事务修改后,MySQL都会保留修改前的数据(版本快照)到undo log中,并且由DB_ROLL_PTR把多个版本快照串联起来形成一个历史记录版本链。
3 快照读和读视图
3.1 快照读和当前读
- 快照读:就是事务读取每条记录的版本快照,而不是当前最新的数据,所以不用加锁。
- 当前读:读取的是最新版本,所以在读取之前需要获得对应记录的锁。
3.2 读视图(readview)
事务在进行快照读的时候会产生读视图,用来判断当前事务可以访问该记录的哪个版本快照。
3.2.1 readview的属性
- m_ids:表示在生成“readview”时,当前系统中没提交事务的“事务id”列表。
- min_trx_id:表示在生成“readview”时,当前系统中没提交读写事务中的最小“事务id”。
- max_trx_id:表示在生成"readview"时,系统中应该分配给下一个事务的“事务id”
- creator_trx_id:表示生成该“readview”的事务的事务"事务id"
3.2.2 readview判断版本链中可用版本流程
1 如果被访问版本的trx_id与readview中的creator_trx_id值相同,表明当前事务在访问自己修改过的记录,该版本可以被当前事务访问;
2 如果被访问版本的trx_id小于readview中的min_trx_id值,表明生成该版本的事务在当前事务生成readview前已经提交,该版本可以被当前事务访问;
3 如果被访问版本的trx_id大于readview中的max_trx_id值,表明生成该版本的事务在当前事务生成readview后才开启,该版本不可以被当前事务访问;
4 如果被访问版本的trx_id在readview的min_trx_id和max_trx_id之间,需要在m_ids中去查找是否存在?
- 如果存在,表示创建readview生成该版本的事务还未提交,该版本不可访问。
- 如果不存在,表明创建readview生成该版本的事务已提交,该版本可以访问。
5 如果当前版本不可访问,则由roll_pointer回滚到上一个版本,重复1-4步骤,直到可以访问为止。
3.3 读取已提交(RC)和可重复读(RR)隔离级别下的快照读
- 读取已提交:每次快照读都会生成一个readview,所以每次读都可以看到别的事务提交的数据。
- 可重复读:第一次快照读会创建一个readview,之后每次使用快照读都使用同一个readview,可以避免不可重复读问题。