玩命加载中 . . .

21-事务隔离级别和MVCC


MySQL 是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就称之为一个会话(Session)。每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分,也就是对于服务器来说可能同时处理多个事务

21.2.1 事务并发执行时遇到的一致性问题

  • 脏写:一个事务修改了另一个未提交事务修改过的数据

  • 脏读:一个事务读到了另一个未提交事务修改过的数据

  • 不可重复读:一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值

  • 幻读:一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来

21.2.2 SQL标准中的4种隔离级别

  • READ UNCOMMITTED:未提交读
  • READ COMMITTED:已提交读
  • REPEATABLE READ:可重复读
  • SERIALIZABLE:可串行化
隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED
READ COMMITTED ×
REPEATABLE READ × ×
SERIALIZABLE × × ×

21.3 MVCC原理

每次对记录进行改动,都会记录一条 undo 日志,每条 undo 日志也都有一个roll_pointer属性(INSERT 操作对应的 undo 日志没有该属性,因为该记录并没有更早的版本),可以将这些 undo 日志都连起来,串成一个链表,称为版本链。版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id

21.3.2 ReadView

需要判断一下版本链中的哪个版本是当前事务可见的

ReadView 中主要包含4个比较重要的内容

  • m_ids:表示在生成 ReadView 时当前系统中活跃的读写事务的事务id列表
  • min_trx_id:表示在生成 ReadView 时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值
  • max_trx_id:表示生成 ReadView 时系统中应该分配给下一个事务的id值
  • creator_trx_id:表示生成该 ReadView 的事务的事务id

访问某条记录时,需要判断记录的某个版本是否可见

  • 如果被访问版本的trx_id属性值与 ReadView 中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问
  • 如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成 ReadView 前已经提交,所以该版本可以被当前事务访问
  • 如果被访问版本的trx_id属性值大于 ReadView 中的max_trx_id值,表明生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问
  • 如果被访问版本的trx_id属性值在 ReadView 的min_trx_idmax_trx_id之间,那就需要判断一下是不是在m_ids列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问

如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录

  • 使用READ COMMITTED隔离级别的事务在每次查询开始时都会生成一个独立的 ReadView
  • 对于使用REPEATABLE READ隔离级别的事务来说,只会在第一次执行查询语句时生成一个 ReadView,之后的查询就不会重复生成了

文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录