InnoDB 的 MVCC ,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列一个保存了行的创建时间,一个保存了行的过期时间(删除时间),存储的是系统版本号。开始一个新的事务,系统版本号都会递增。事务开始时刻的版本号会作为事物的版本号,用来和查询到的每行记录的版本号进行比较。REPEATABLE READ隔离级别下,MVCC 的具体操作:

    SELECT
    InnoDB 会根据以下两个条件检查每行记录

    • InnoDB 只查找版本早于当前事务的版本的数据行,这样可以确保事务读取的行,要么是在事务开始之前已经存在,要么是事务自身插入或修改过的
    • 行的删除版本要么未定义,要么大于当前事务版本号,可以确保事务读取到的行,在事务开始之前未被删除

    只有符合上述两个条件的记录,才能返回作为查询结果

    INSERT
    InnoDB 为新插入的每一行保存当前系统版本号作为行版本号

    DELETE
    InnoDB 为删除的每一行保存当前系统版本号作为行删除标识

    UPDATE
    InnoDB 为插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识

    保存这两个额外系统版本号,使大多数操作不用加锁,使得读数据的操作很简单,性能很好,能保证读到是符合标准的行。不足之处在于每行记录需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。
    MVCC 只在 REPEATABLE READREAD COMMITED 两个隔离级别下工作,其他的隔离级别都和 MVCC 不兼容,因为 READ UNCOMMITED 总是读取最新的数据行,而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行加锁。