【问题标题】:InnoDB MySQL Select Query LockingInnoDB MySQL 选择查询锁定
【发布时间】:2017-10-31 17:26:57
【问题描述】:

我有一个可重复读取的隔离级别,我正在制作: Select * From example查询。我在https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html 中读到 select...from 查询使用来自快照的一致读取,因此没有对行或表设置锁定。这是否意味着,在选择之后但在选择查询结束之前发起的更新、插入或删除仍然能够运行,即使修改不会显示在选择结果中?

【问题讨论】:

    标签: mysql innodb


    【解决方案1】:

    是的,您可以在现有事务持有数据的可重复读取快照时更新/插入/删除。

    这是由多版本并发控制或 MVCC 实现的。

    这是一种奇特的说法,即 RDBMS 保留同一行的多个版本,以便可重复读取的快照可以继续读取旧版本,只要它们需要(即,只要它们的事务快照存在)。

    如果存在由在您的事务开始后提交的事务创建的行版本,您应该看不到该行版本。每个行版本在内部保留一些关于创建它的事务的元数据,每个事务都知道如何使用它来确定它是否应该看到行版本。

    最终,所有可能对旧行版本感兴趣的事务都完成了,MVCC 可以“清理”过时的行版本。

    【讨论】:

    • If a row version exists that was created by a transaction that committed after your transaction started, you shouldn't be able to see that row version. - 理论上是正确的,就 mysql 而言并非总是如此
    • 使用可重复读事务隔离(这是默认设置)并进行非锁定读时会出现这种情况。
    • 不,事实并非如此。请参阅我的答案中链接的 mysql 手册页。
    • 这种行为前段时间差点让我心脏病发作——我已经很好地吸取了教训:)
    • 我了解到更新和锁定读取总是锁定和查看最近提交的行,即使您使用可重复读取隔离级别。在使用其他没有这样做的 SQL 实现之后,这让我感到惊讶。但另一种方法是阻止更新,直到其他事务完成(这就是 InterBase/FireBird 所做的)。
    【解决方案2】:

    基本上,是的,情况就是这样,但有些复杂。

    默认情况下,repeatable read 中的select ... from ... 不会对底层数据进行任何锁定并建立快照。

    如果另一个事务更改了基础数据,那么如果在第一个事务的范围内再次选择相同的记录,则这些更改不会反映。到目前为止一切顺利。

    但是,如果您的第一个事务在快照建立后修改了受其他已提交事务影响的记录,那么其他事务所做的修改也将对第一个事务可见,因此您的快照可能在之后不一致全部。

    有关此功能的更多详细信息,请参阅 MySQL 手册的Consistent Nonlocking Reads 章节中的第一个注释部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多