【问题标题】:Why I shouldn't use "Repeatable Read" with locking reading (select..for update)"?为什么我不应该使用“可重复读取”和锁定读取(选择..for update)”?
【发布时间】:2018-02-24 02:43:58
【问题描述】:

在Mysql文档中:“https://dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks-handling.html

它提到:“如果您使用锁定读取(SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE),请尝试使用较低的隔离级别,例如 READ COMMITTED。

谁能告诉我为什么我不能使用“可重复阅读”?例子会很好。

干杯

【问题讨论】:

  • 不,不一样,我想知道为什么我不能将“可重复读取”与“选择....更新”一起使用。
  • edit你的问题,干杯

标签: mysql deadlock read-committed


【解决方案1】:

如果你使用 read-committed,InnoDB 会避免使用某些类型的锁。这可以帮助您避免死锁。

我为此设计了一个完整的演示文稿:InnoDB Locking Explained with Stick Figures

但您实际上永远无法避免 100% 的死锁情况。它们不是错误,它们是并发系统的自然组成部分。您可以减少死锁发生的频率,但您不妨习惯一些。设计代码以捕获异常并在出现死锁时重试数据库操作。

【讨论】:

    【解决方案2】:

    原因是,如果表中不存在记录,它看起来像 SELECT ... FOR UPDATE 在共享模式下(或类似的东西 - 它没有记录在任何地方)对于不存在的记录之后的索引记录REPEATABLE READ 隔离模式已启用。

    让我们尝试一个简单的表t 的示例,该表在REPEATABLE READ 隔离模式下为空。

    t1> SELECT * FROM t WHERE id = 1 FOR UPDATE;
        no rows found, next-key lock acquired in shared mode
    t2> SELECT * FROM t WHERE id = 1 FOR UPDATE;
        no rows found, next-key lock acquired in shared mode
    t1> INSERT INTO t (id) VALUES (1);
        transaction t1 is blocked by t2
    t2> INSERT INTO t (id) VALUES (1);
        transaction t2 is blocked by t1 - deadlock
    

    即使第二个 SELECT 和 INSERT 将使用id=2,也会发生死锁,因为它也落入了相同的间隙,由SELECT ... FOR UPDATE 锁定,在t1 中执行。如果桌子是空的,这个间隙是无穷大。如果表不为空,则插入不同记录的死锁概率较小,但仍然很大(这取决于表中有多少间隙以及插入到表末尾的频率 - 最大间隙)。

    发生这种情况是因为来自t1t2SELECT ... FOR UPDATE 在记录不存在时不会相互阻止。对于现有记录,它会在t1 中的记录上获取X(独占)锁,因此t2 将被阻止,直到t1 被提交或回滚。但是如果记录不存在 - 它会在间隙上获取 S(共享)next-key 锁(我不确定它是否真的是 S 锁(它没有在任何地方记录),但是 MySQL 还允许如何在同一个间隙上同时获取 2 个锁?)。这就是这里出现死锁的主要原因——t1t2 都试图在间隙上获得 IX(插入意图)锁,然后在插入的记录上获得 X 锁,但都因为锁而相互等待,被SELECT ... FOR UPDATE收购。

    使用READ COMMITED事务隔离级别时不存在此问题。如果没有找到记录并且使用了READ COMMITED 隔离级别,SELECT ... FOR UPDATE 不会持有任何锁。所以第一个INSERT 会成功。第二个INSERT 将被第一个INSERT 获取的独占锁阻塞,在提交t1 之后,第二个INSERT 将抛出Duplicate entry '1' for key 'PRIMARY'

    您现在可以认为这种情况并不比僵局更好。只是另一个错误。但现在想象第二个INSERT 尝试插入一条带有id=2 的记录。在这种情况下,t1 不会阻止它,两个事务都会成功。这对于某些应用程序来说是一个很大的不同

    【讨论】:

      猜你喜欢
      • 2016-02-20
      • 2020-07-15
      • 1970-01-01
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      • 2019-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多