防止你的php应用程序中的mysql死锁使用SELECT ... LOCK IN SHARE MODE

时间:2011-10-17 19:43:59

标签: php mysql select innodb deadlock

堆栈:

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

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

我很关心创建死锁,其中脚本A锁定脚本B需要的数据,脚本B锁定脚本A需要的数据。我怎样才能在我的应用程序中解决这个问题?

另外,我在网站数据库中只使用innodb,所以我不需要担心表锁是否正确?

1 个答案:

答案 0 :(得分:0)

在MySQL文档中,页面14.6.8.1. InnoDB Lock Modes讨论(靠近页面底部)由第一个客户端请求具有“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”来解决。这会导致第一个客户端从头开始获取写锁定,然后它就不必等待第二个客户端。

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