在使用SELECT的php应用程序中防止mysql死锁..在共享模式下锁定


Preventing mysql deadlocks in your php application that uses SELECT... LOCK IN SHARE MODE

堆栈:

如果我理解SELECT。。。在共享模式下正确锁定,您可以将其放入mysql事务中,以选择您将在该事务中使用的行,以便从其他会话的写入/删除操作中"锁定"那些选定的行(但其他会话仍然可以读取行(,直到您的事务完成,此时,用SELECT LOCK IN SHARE MODE语句锁定的行将被释放,以便其他会话可以访问它们进行写入/删除等操作。

这正是我想要的评论表。每当在我的网站上向帖子添加评论时,我需要锁定与该帖子相关的所有评论行,同时更新所有锁定行上的一些元数据。如果同时提交两条评论,我不希望他们同时访问相关的评论行,因为他们基本上会把对方(和元数据(搞砸。因此,我想将SELECT LOCK IN SHARE MODE合并到注释上传脚本中,这样运行锁定查询的第一个会话就可以完全控制注释行,直到它完成整个事务为止(稍微慢一点的脚本必须等到第一个脚本的整个事务执行完为止(。

我很担心创建死锁,脚本a锁定脚本B需要的数据,脚本B锁定脚本a需要的数据。如何在我的申请中绕过这一点?

另外,我在我的网站数据库中只使用innodb,所以我不需要担心表锁,对吗?

在MySQL文档中,第14.6.8.1页。InnoDB锁定模式讨论(在页面底部附近(由第一个客户端用"Lock IN SHARE MODE"请求读取锁定和第二个客户端因删除而请求写入锁定引起的死锁情况。第二个客户端被第一个客户端的读锁阻塞,所以它的写锁被排队。但是,当第一个客户端尝试删除时,会发生以下情况:

这里发生死锁是因为客户端A需要X(独占(锁来删除一行但是,由于客户端B的原因,无法授予该锁定请求已经有一个X锁请求,正在等待客户端a释放其S(共享(锁。A持有的S锁也不能升级为X锁定,因为B先前请求X锁定。因此InnoDB为客户端A生成一个错误并释放其锁。在那此时,可以批准客户端B的锁定请求,并且B删除行。

如果我正确理解这一点,我认为第一个客户端使用FOR UPDATE而不是"LOCK IN SHARE MODE"可以解决这个问题。这导致第一个客户端从一开始就获得写锁定,然后它就不必等待第二个客户端。

在查询和更新语句周围使用事务,锁定将一直保持到提交事务为止。不需要其他表锁。