面试题答案
一键面试实现原理
- 读不阻塞写:
- MVCC 基于数据版本,读取时不会加锁。当写入操作发生时,新数据版本生成,老版本数据依然存在。读取操作根据事务的一致性视图(read - view)去读取特定版本的数据,而不是直接读取最新数据。这样写入操作创建新数据版本的过程不会影响读取操作,所以读不阻塞写。
- 写不阻塞读:
- 写入操作只对需要修改的数据行加行锁,且只在修改期间持有锁。读取操作基于版本链获取数据,无需等待写入操作释放锁。只要写入操作不涉及读取操作所依赖的版本链上的数据,写操作就不会阻塞读操作。
关键数据结构
- 数据行的隐藏列:
- DB_TRX_ID:记录最近一次对该数据行进行修改(插入、更新、删除)的事务 ID。
- DB_ROLL_PTR:回滚指针,指向该数据行的上一个版本(即 undo log 中的记录),通过这个指针可以构建版本链。
- undo log:
- 用于存储数据的旧版本。当数据修改时,旧版本的数据会被记录到 undo log 中,配合数据行的隐藏列形成版本链。比如在更新操作时,会把旧的数据值记录到 undo log 中,通过回滚指针建立联系。
- 事务的一致性视图(read - view):
- 每个事务在启动时会生成一个一致性视图。它记录了当前系统中活跃(未提交)的事务 ID 列表。在读取数据时,根据该视图来判断数据的可见性,决定读取哪个版本的数据。
关键机制
- 版本链的构建:
- 每次数据修改时,旧版本数据被记录到 undo log 中,同时数据行的回滚指针指向 undo log 中的记录,从而构建版本链。例如,对某条数据行进行多次更新,每次更新都会生成新的版本记录到 undo log 中,并调整回滚指针,后续读取操作可以根据版本链找到符合一致性视图要求的版本。
- 数据可见性判断:
- 当事务读取数据时,根据其一致性视图和数据行的 DB_TRX_ID 进行判断。如果数据行的 DB_TRX_ID 小于一致性视图中最小的活跃事务 ID,说明该版本是在当前事务启动前就已提交的事务生成的,该版本对当前事务可见;如果数据行的 DB_TRX_ID 大于一致性视图中最大的活跃事务 ID,说明该版本是在当前事务启动后生成的,该版本对当前事务不可见;如果数据行的 DB_TRX_ID 在一致性视图的活跃事务 ID 列表中,且该事务未提交,该版本对当前事务不可见,需要沿着版本链继续查找可见版本。