【发布时间】:2015-12-25 23:17:03
【问题描述】:
这两个锁读子句的确切区别是什么:
SELECT ... FOR UPDATE
和
SELECT ... LOCK IN SHARE MODE
为什么你需要使用一个而不是另一个?
【问题讨论】:
标签: mysql transactions locking innodb acid
这两个锁读子句的确切区别是什么:
SELECT ... FOR UPDATE
和
SELECT ... LOCK IN SHARE MODE
为什么你需要使用一个而不是另一个?
【问题讨论】:
标签: mysql transactions locking innodb acid
我一直试图了解两者之间的区别。我将记录我的发现,希望对下一个人有用。
LOCK IN SHARE MODE 和 FOR UPDATE 都确保没有其他事务可以更新选定的行。两者的区别在于读取数据时如何处理锁。
LOCK IN SHARE MODE 不会阻止另一个事务读取被锁定的同一行。
FOR UPDATE 防止对同一行进行其他锁定读取(非锁定读取仍然可以读取该行;LOCK IN SHARE MODE 和 FOR UPDATE 是锁定读取)。
这在更新计数器等情况下很重要,在这种情况下,您读取 1 个语句中的值并更新另一个语句中的值。这里使用LOCK IN SHARE MODE 将允许2 个事务读取相同的初始值。因此,如果两个事务的计数器都增加了 1,则结束计数可能只会增加 1 - 因为两个事务最初读取的值相同。
使用FOR UPDATE 将锁定第二个事务,使其无法读取值,直到第一个事务完成。这将确保计数器增加 2。
【讨论】:
For Update --- 您通知 Mysql 所选行可以在接下来的步骤中更新(在此事务结束之前),因此 mysql 不会授予对同一组行的任何读锁到当时的任何其他交易。另一个事务(无论是读/写)应该等到第一个事务完成。
For Share- 向 Mysql 表明您从表中选择行仅用于读取目的,而不是在事务结束之前进行修改。任意数量的事务都可以访问行上的读锁。
注意:如果这个语句(For update, For share)没有正确使用,就有可能出现死锁。
【讨论】:
无论哪种方式,您的数据的完整性都会得到保证,这只是数据库如何保证它的问题。它是通过在事务相互冲突(即 FOR SHARE)时引发运行时错误来做到这一点,还是通过序列化任何相互冲突的事务(即 FOR UPDATE)来做到这一点?
FOR SHARE(又名 LOCK IN SHARE MODE):由于死锁,事务面临更高的失败概率,因为它们延迟阻塞直到收到更新语句的那一刻(此时它们要么阻塞直到所有读锁被释放,要么如果正在进行另一次写入,则会因死锁而失败)。但是,只有一个客户端阻塞并最终成功:其他客户端如果尝试更新,则会因死锁而失败,因此只有一个客户端会成功,其余客户端将不得不重试其事务。
更新:事务不会因为死锁而失败,因为它们不允许同时运行。例如,这可能是可取的,因为如果所有更新都在所有客户端上序列化,则更容易推理多线程。但是,它限制了您可以实现的并发性,因为所有其他事务都会阻塞,直到第一个事务完成。
专业提示:作为练习,我建议您花一些时间在命令行上使用本地测试数据库和几个 mysql 客户端来证明这种行为。这就是我自己最终理解差异的方式,因为在你看到它之前它可能非常抽象。
【讨论】: