隐式字段

每行记录除了我们自定义的字段外,还有数据库隐式定义的DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段

  • DB_TRX_ID

6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID

  • DB_ROLL_PTR

7byte,回滚指针,指向这条记录上一个版本(存储于rollback segment里)

  • RB_ROW_ID

6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引

  • 实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了

image.png

如上图,DB_ROW_ID是数据库默认为该行记录生成的唯一隐式主键,DB_TRX_ID是当前操作该记录的事务ID,而DB_ROLL_PTR是一个回滚指针,用于配合undo日志,指向上一个旧版本

undo日志

undo log是为回滚而用,具体内容就是copy事务前的数据库内容(行)到undo buffer,在适合的时间把undo buffer中的内容刷新到磁盘。undo buffer与redo buffer一样,也是环形缓冲,但当缓冲满的时候,undo buffer中的内容会也会被刷新到磁盘;与redo log不同的是,磁盘上不存在单独的undo log文件,所有的undo log均存放在主ibd数据文件中(表空间),即使客户端设置了每表一个数据文件也是如此。

undo log主要分为两种:

  • insert undo log
    代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
  • update undo log
    事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除

image.png

当执行查询sql的时候会生成一致性视图 read-view,由执行查询时候所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id)(包含已提交和未提交)组成,查询的数据结果需要跟read-view做对比从而的得到快照结果

image.png

undo版本链是如何生成的:

  1. DB_ROW_ID = 1 的这行记录加排他锁
  2. 把该行原本的值拷贝到 undo log 中,DB_TRX_IDDB_ROLL_PTR 都不动
  3. 修改该行的值这时产生一个新版本,更新 DATA_TRX_ID 为修改记录的事务 ID,将 DATA_ROLL_PTR 指向刚刚拷贝到 undo log 链中的旧版本记录,这样就能通过 DB_ROLL_PTR 找到这条记录的历史版本。如果对同一行记录执行连续的 UPDATEUndo Log 会组成一个链表,遍历这个链表可以看到这条记录的变迁
  4. 记录 redo log,包括 undo log 中的修改

image.png
按照规则版本链中查询最新的记录
因为默认是可重复读,那么readview 都是可沿用下来的,如果是读已提交那么每次都会更新最新的
image.png
image.png
当执行第一条查询sql的时候从日志的上到下开始读取发现当前最新的事务id是300,然后根据read-view进行对比,发现落在黄色区域,并且没有在数组中,那么就是可见的 查询出的结果就是lilei300

另外一种情况:
image.png
image.png

这个时候因为不是一个会话所以无需遵守 可重复读规则,那么 当前未提交数组就变成了了 200 最大事务是300