MySQL InnoDB:"FOR UPDATE"和"LOCK IN SHARE MODE"之间的区别

pje*_*pje 19 mysql innodb locking transactions acid

两个锁定读取子句之间的确切区别是什么:

SELECT ... FOR UPDATE
Run Code Online (Sandbox Code Playgroud)

SELECT ... LOCK IN SHARE MODE 
Run Code Online (Sandbox Code Playgroud)

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

Ais*_*war 40

我一直试图理解两者之间的区别.我将记录我发现的内容,希望它对下一个人有用.

双方LOCK IN SHARE MODEFOR UPDATE确保任何其它事务可以更新选择的行.两者之间的区别在于它们在读取数据时如何处理锁定.

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

FOR UPDATE阻止同一行的其他锁定读取(非锁定读取仍然可以读取该行; LOCK IN SHARE MODE并且FOR UPDATE是锁定读取).

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

使用FOR UPDATE会锁定第二个事务,直到第一个事务完成为止.这将确保计数器增加2.

  • 根据 https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html “至少其中一个最终陷入死锁” - 没有像你所说的那样将计数器增加 1 而不是 2 . 任何想法为什么会发生死锁? (4认同)
  • 如果两个事务在 SHARE 模式下锁定该行,则任何一个事务都无法更新该行 - 当其他事务持有锁时不允许更新。在这种情况下真正会发生的是,两者之一将超时,释放其锁,然后另一个将成功更新该行。因此,一方面,数据库将保持一致,但另一方面,您最终会遇到不必要的故障。 (2认同)

小智 6

对于更新---您正在通知Mysql可以在接下来的步骤中(此事务结束之前)更新选定的行,以便mysql不会将同一行集上的任何读取锁授予任何其他行当时的交易。另一个事务(无论是否为读/写)应等待第一个事务完成。

对于共享-向Mysql表示您正在选择表中的行仅出于读取目的,而不是在事务结束之前进行修改。任意数量的事务都可以访问行上的读取锁。

注意:如果未正确使用此语句(用于更新,用于共享),则有可能导致死锁。


kar*_*gog 5

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

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

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

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