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

标签 php mysql select innodb deadlock

堆栈:

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

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

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

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

最佳答案

在 MySQL 文档中,页面 14.6.8.1. InnoDB Lock Modes讨论(在页面底部附近)由第一个客户端使用“LOCK IN SHARE MODE”请求读锁而第二个客户端由于删除请求写锁而导致的死锁情况。第二个客户端被第一个客户端的读锁阻塞,所以它的写锁被排队。但是当第一个客户端尝试删除时,会发生以下情况:

Deadlock occurs here because client A needs an X (exclusive) lock to delete the row. However, that lock request cannot be granted because client B already has a request for an X lock and is waiting for client A to release its S (shared) lock. Nor can the S lock held by A be upgraded to an X lock because of the prior request by B for an X lock. As a result, InnoDB generates an error for client A and releases its locks. At that point, the lock request for client B can be granted and B deletes the row from the table.

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

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

关于php - 防止使用 SELECT...LOCK IN SHARE MODE 的 php 应用程序中的 mysql 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7798720/

相关文章:

php - 没有数据从 Android 插入到 MySQL

php - 如何在 PHP 中处理 IPv6 地址?

mysql - 找不到连接器/网络引用

使用 Null 值选择和计数

mysql - 使用分组计算对 MySQL 中自己 ID 的引用

sql - 在这个特定的上下文中是否有更有效的方法来编写我的过滤器?

php - 统计与表中数据相同的单词数据

java - 从 MySQL 获取最后一个 id

mysql - 将 MySQL 脚本转换为 SQL Server

php - 奇怪的 mysql,显示来自 myAdmin 的 0 个结果集,但在 PHP PDO 中返回行