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



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

SELECT ... FOR UPDATE

SELECT ... LOCK IN SHARE MODE 

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

我一直在努力理解两者之间的区别。我将把我的发现记录下来,希望对下一个人有用。

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

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

FOR UPDATE阻止对同一行的其他锁读操作(非锁读操作仍然可以读该行;LOCK IN SHARE MODEFOR UPDATE正在锁读)。

这在更新计数器等情况下很重要,在一个语句中读取值并在另一个语句中更新值。这里使用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):事务面临死锁失败的可能性更高,因为它们延迟阻塞直到收到更新语句的那一刻(此时它们要么阻塞直到所有的读锁被释放,要么由于死锁而失败如果另一个写正在进行中)。然而,只有一个客户端阻塞并最终成功:其他客户端如果尝试更新将失败并死锁,因此只有其中一个客户端会成功,其余的客户端将不得不重试他们的事务。

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

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