MySQL事务分类与验证

MySQL事务特性

  • 原子性
    整个事务是不可分割的最小执行单元,要么全部成功,要么全部失败
  • 一致性
    总是从一个一致性状态转换到另一个一致状态(不存在中间态)
  • 隔离性
    一个事务所做修改在最终提交前,对其他事务不可见
  • 持久性
    一旦事务提交,其修改会永久保存到数据库中

事务的隔离级别以及对应问题

事务分类

事务分类 描述 事务ID
读事务 整个事务中只有读操作,则一直是读事务 使用事务对象地址计算得到唯一事务ID,比较大的数值
读写事务 事务中遇到第一个更新语句升级为读写事务 分配全局唯一的读写事务ID

两个问题

  1. 事务是在使用 begin / start transaction 时真正开启的吗?
  2. 读事务、读写事务分别在什么时候得到事务ID?

验证使用的MySQL版本与测试表

两个命令行工具

1
2
SHOW ENGINE INNODB STATUS \G  -- 查看当前innodb引擎的监控信息
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX \G -- 查看当前开启事务的概览信息

开启读事务验证

小结:

  1. 读事务在遇到第一条读操作SQL语句时开启
  2. 获得一个很大的事务ID

其他知识点

  1. 读事务ID在某种情况下会被缓存起来
  2. 同一个session会话中,多个连续的读事务,获得的读事务ID一样
  3. 读事务ID不是系统全局唯一的读写事务ID,不会被记录到undo log中

开启读写事务验证

小结:

  1. 读写事务在遇到第一条写操作语句时开启
  2. 被分配一个比较小的全局事务ID

事务升级

事务没有分类时存在的问题

需要知道的:数据库读写操作比例大部分基本符合 8/2规律。

在以前的老版本,事务没有分为读事务、读写事务。那么:

  1. 每个SQL执行语句都是一个执行事务 (即使没有显式的使用事务声明语句)
  2. 每个事务都会占用一个系统全局唯一事务ID
  3. 事务视图拍快照时,记录的当前活跃事务数组中包含80%读操作事务ID
  4. 事务会分配额外的空间来处理一些逻辑

造成问题:

  1. 读操作占用大量全局事务ID(全局ID的损耗)
  2. 活跃事务数组包含大量无用读操作事务ID(空间损耗)
  3. 判断可见性时,需要遍历大量无用读事务ID(计算性能损耗)

事务分类后的好处

事务分类的好处:

  1. 读事务不再占用全局事务ID (多个连续的读事务可以共用同一个读事务ID)
  2. 活跃事务列表中只有读写事务ID (减小了活跃事务数组的长度)
  3. 判断可见性时,只遍历少量读写事务ID (减小遍历时的性能损耗)
  4. 读事务不再分配额外的空间 (减小空间占用)