【问题标题】:MySQL InnoDB: Difference Between `FOR UPDATE` and `LOCK IN SHARE MODE`MySQL InnoDB:“FOR UPDATE”和“LOCK IN SHARE MODE”之间的区别
【发布时间】:2015-12-25 23:17:03
【问题描述】:

这两个锁读子句的确切区别是什么:

SELECT ... FOR UPDATE

SELECT ... LOCK IN SHARE MODE 

为什么你需要使用一个而不是另一个?

【问题讨论】:

标签: mysql transactions locking innodb acid


【解决方案1】:

我一直试图了解两者之间的区别。我将记录我的发现,希望对下一个人有用。

LOCK IN SHARE MODEFOR UPDATE 都确保没有其他事务可以更新选定的行。两者的区别在于读取数据时如何处理锁。

LOCK IN SHARE MODE 不会阻止另一个事务读取被锁定的同一行。

FOR UPDATE 防止对同一行进行其他锁定读取(非锁定读取仍然可以读取该行;LOCK IN SHARE MODEFOR UPDATE 是锁定读取)。

这在更新计数器等情况下很重要,在这种情况下,您读取 1 个语句中的值并更新另一个语句中的值。这里使用LOCK IN SHARE MODE 将允许2 个事务读取相同的初始值。因此,如果两个事务的计数器都增加了 1,则结束计数可能只会增加 1 - 因为两个事务最初读取的值相同。

使用FOR UPDATE 将锁定第二个事务,使其无法读取值,直到第一个事务完成。这将确保计数器增加 2。

【讨论】:

  • 根据dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html“至少其中一个最终陷入僵局” - 如您所说,不是将计数器增加 1 而不是 2。任何想法为什么会发生死锁?
  • 如果两个事务以 SHARE 模式锁定该行,那么任何一个都无法更新该行 - 当其他事务持有锁时,不允许更新。在这种情况下真正会发生的是,两者中的一个会超时,释放它的锁,然后另一个会成功更新行。因此,一方面,数据库将保持一致,但另一方面,您最终会出现不必要的故障。
  • 在这种情况下,如果由于死锁而无法真正更新行,如果还有其他事务也持有 SHARE 模式锁,那么 SHARE 模式锁的实际用例是什么?只有当您不打算 UPDATE/DELETE,而是想依赖读取一致性时?
  • 答案大部分是正确的,但是如果使用 FOR SHARE 的两个事务之间存在这样的死锁,那么一个事务会成功而另一个不会。如果您使用测试数据库和交互式 mysql 客户端尝试给定示例,您将观察到以下行为:两个事务都将读取计数器值 1,但只有一个事务将成功将其更新为值 2。无论哪个先获得更新将由于另一个事务中的读锁而阻塞。当另一个事务尝试更新它会由于死锁而失败,然后第一个将解锁并成功。
【解决方案2】:

For Update --- 您通知 Mysql 所选行可以在接下来的步骤中更新(在此事务结束之前),因此 mysql 不会授予对同一组行的任何读锁到当时的任何其他交易。另一个事务(无论是读/写)应该等到第一个事务完成。

For Share- 向 Mysql 表明您从表中选择行仅用于读取目的,而不是在事务结束之前进行修改。任意数量的事务都可以访问行上的读锁。

注意:如果这个语句(For update, For share)没有正确使用,就有可能出现死锁。

【讨论】:

    【解决方案3】:

    无论哪种方式,您的数据的完整性都会得到保证,这只是数据库如何保证它的问题。它是通过在事务相互冲突(即 FOR SHARE)时引发运行时错误来做到这一点,还是通过序列化任何相互冲突的事务(即 FOR UPDATE)来做到这一点?

    FOR SHARE(又名 LOCK IN SHARE MODE):由于死锁,事务面临更高的失败概率,因为它们延迟阻塞直到收到更新语句的那一刻(此时它们要么阻塞直到所有读锁被释放,要么如果正在进行另一次写入,则会因死锁而失败)。但是,只有一个客户端阻塞并最终成功:其他客户端如果尝试更新,则会因死锁而失败,因此只有一个客户端会成功,其余客户端将不得不重试其事务。

    更新:事务不会因为死锁而失败,因为它们不允许同时运行。例如,这可能是可取的,因为如果所有更新都在所有客户端上序列化,则更容易推理多线程。但是,它限制了您可以实现的并发性,因为所有其他事务都会阻塞,直到第一个事务完成。

    专业提示:作为练习,我建议您花一些时间在命令行上使用本地测试数据库和几个 mysql 客户端来证明这种行为。这就是我自己最终理解差异的方式,因为在你看到它之前它可能非常抽象。

    【讨论】:

    • 如果(比如说)您有 2 个并发事务尝试锁定相同的两行(或索引范围等)并且它们以不同的顺序执行它们(即trans1锁定row1,trans2锁定row2,然后各自尝试锁定另一行=>死锁,其中一个事务将超时)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-22
    • 1970-01-01
    相关资源
    最近更新 更多