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