2011-10-17 69 views
1

堆栈PHP应用程序:防止MySQL的死锁在使用SELECT ... LOCK IN SHARE MODE

如果我没有理解SELECT ... LOCK IN SHARE MODE正确的,你可以把它变成一个MySQL的交易选择在该事务期间您将使用的行将从其他会话的写入/删除操作中“锁定”这些选定行(但其他会话仍可以读取行),直到事务完成,此时将锁定行SELECT SHOCK IN SHARE MODE语句被释放,所以其他会话可以访问它们进行写入/删除等。

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

我是一个但担心在脚本A锁定脚本B需要的数据的情况下创建死锁,而脚本B锁定了脚本A需要的数据。我如何在应用程序中解决这个问题?

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

感谢,

Billmalarky

回答

0

在MySQL文档中,14.6.8.1. InnoDB Lock Modes页面讨论(靠近页面底部)所造成的第一个客户端请求与“SHARE模式锁定读锁定的死锁情况“并且第二个客户端因为删除而请求写入锁定。第二个客户端被第一个客户端的读锁锁定,所以它的写锁被排队。但是,当第一个客户端然后尝试做了删除,将发生以下情况:因为客户端A需要一个X(独占)锁删除 行

发生死锁在这里。但是,该锁定请求不能被授予,因为客户端B 已经有X锁的请求,并且正在等待客户端A到 释放其S(共享)锁定。由于B先前请求X锁,因此A所持有的S锁也不能升级到X 锁。因此,InnoDB为客户端A生成一个错误并释放它的锁。在 点上,可以授予客户端B的锁定请求,并且B从表中删除 行。

如果我理解正确此,我认为这个问题可以通过使用FOR UPDATE而不是“锁定共享模式”的第一个客户端来解决。这会导致第一个客户端从头开始写入锁定,然后永远不必等待第二个客户端。

在查询和更新语句周围使用事务,锁将一直保留,直到您提交事务。没有其他表锁应该是必要的。