1. 注意的是事务的启动时机:
    begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句,事务才真正启动。如果你想要马上启动一个事务,可以使用start transaction with consistent snapshot 这个命令。

  2. InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”指的就是,启动了但还没提交。

    数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。

    这样,对于当前事务的启动瞬间来说,一个数据版本的row trx_id,有以下几种可能:

    • 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
    • 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
    • 如果落在黄色部分,那就包括两种情况
      a. 若 row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
      b. 若 row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
  3. 一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以外,有三种情况:

    • 版本未提交,不可见;
    • 版本已提交,但是是在视图创建后提交的,不可见;
    • 版本已提交,而且是在视图创建前提交的,可见。

注意事项:

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
  • 在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图;
  • 在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议;
  • 更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。