InnoDB的MVCC
InnoDB的MVCC(多版本并发控制)通过维护数据行的历史版本,使得读写操作互不阻塞。其底层实现主要依赖于三个核心组件、一套可见性判断算法,以及Read View的生成时机。
一、 MVCC的三大核心组成
1. 隐藏列(Hidden Columns) InnoDB在聚簇索引的每一行记录中,都会默认添加三个隐藏字段:
-
DB_TRX_ID(6字节): 记录最近一次插入或修改该行数据的事务ID。
-
DB_ROLL_PTR(7字节): 回滚指针,指向Undo Log中该行数据的上一个版本。
-
DB_ROW_ID(6字节): 隐藏的自增行ID(仅在表没有主键或非空唯一索引时生成,与MVCC版本控制无直接关系,但属于隐藏列)。
2. Undo Log(回滚日志与版本链) 当一个事务修改某行数据时,InnoDB会将该行修改前的数据记录到Undo Log中。通过行记录上的DB_ROLL_PTR指针,当前行数据和Undo Log中的历史数据被连接成一个单向链表,这就是版本链。链表头是最新版本数据,链表尾是最早版本数据。
3. Read View(读视图) Read View是事务执行快照读(如普通的SELECT)时,生成的一个数据可见性快照。它记录了当前系统中活跃(未提交)的事务状态。Read View包含四个核心字段:
-
m_ids: 生成Read View时,当前系统中所有活跃事务的ID列表。
-
min_trx_id:
m_ids中最小的事务ID。 -
max_trx_id: 生成Read View时系统将分配给下一个事务的ID(即当前系统中最大事务ID + 1)。
-
creator_trx_id: 生成该Read View的当前事务ID。
二、 可见性判断规则
当事务读取某行数据时,会顺着版本链从最新版本开始,逐个比对该版本记录的DB_TRX_ID与当前Read View,直到找到第一个可见的版本。比对规则如下:
-
DB_TRX_ID == creator_trx_id:该版本由当前事务自己修改,可见。
-
DB_TRX_ID < min_trx_id:该版本在Read View生成前就已经提交,可见。
-
DB_TRX_ID >= max_trx_id:该版本在Read View生成之后才产生,属于未来的事务操作,不可见。
-
min_trx_id <= DB_TRX_ID < max_trx_id:需要判断该
DB_TRX_ID是否在活跃事务列表m_ids中:-
如果在
m_ids中:说明生成Read View时该事务尚未提交,不可见。 -
如果不在
m_ids中:说明生成Read View时该事务已经提交,可见。
-
如果当前版本不可见,就会沿着DB_ROLL_PTR指针找到上一个版本,继续套用上述规则,直到找到可见版本或到达链表末尾。
三、 RC与RR隔离级别下的差异
RC(Read Committed,读已提交)和RR(Repeatable Read,可重复读)都通过上述MVCC机制实现快照读,它们的唯一区别在于Read View的生成时机不同:
-
RC(读已提交):每次读取都生成新的Read View 在RC级别下,事务中的每一次
SELECT操作都会生成一个全新的Read View。这意味着,如果在两次查询之间有其他事务提交了修改,新生成的Read View会将已提交的事务排除在m_ids之外,从而使得当前事务能够读取到最新的已提交数据。这导致了不可重复读现象。 -
RR(可重复读):仅在第一次读取时生成Read View 在RR级别下,事务只在执行第一次
SELECT操作时生成一个Read View,并在整个事务期间复用这个Read View。无论其他事务在此期间如何修改并提交数据,当前事务的Read View始终保持初始状态。因此,它查询到的数据快照始终一致,从而解决了不可重复读问题。
- 点赞
- 收藏
- 关注作者
评论(0)