MySQL中奇怪的锁定问题

时间:2010-06-19 10:43:57

标签: mysql locking

我的服务器常常挂起,MySQL会显示以下进程列表:

流程1: 时间:24 用户:工人 状态:已锁定 信息:LOCK TABLES tRatings WRITE,tUsers WRITE

流程2: 时间:24 用户:工人 状态:正在更新 信息:UPDATE tUsers SET fGender ='1'WERE fID = 232049

流程3: 时间:24 用户:工人 状态:已锁定 信息:LOCK TABLES tClients READ,tUsers uA READ,tUsers aB READ,tNexts READ

所有表都是InnoDB,我使用显式的LOCK TABLES来防止InnoDB死锁发生。

我的问题是我根本不明白这里出了什么问题!可以请有人解释一下,为什么他只是在接下来的操作上没有表现?相反,所有进程都不会(在此示例中)24秒内无效。

谢谢,

1 个答案:

答案 0 :(得分:1)

  

我的服务器常常挂起[...]所有表都是InnoDB,我使用显式LOCK TABLES来阻止InnoDB死锁发生。

你没有阻止死锁。您正在阻止自动死锁检测。让我解释一下:

当您有两个(或更多)进程争用同一资源但以不同顺序竞争时,会发生死锁。例如:

  • 进程A需要资源2,然后是资源1.它成功获取资源2 ...
  • 但是有一个上下文切换!进程B出现并获取资源1,然后尝试获取资源2,但它不能,因为A已保留它(在事务中或在锁中),因此B被置于保持状态。
  • 上下文切换! A再次出现并尝试获取资源1,但它由进程B保持。
  • 现在正在等待B,B正在等待A.这是一个僵局。

当在事务中发生这种情况时,数据库引擎可以检测到正在发生死锁并终止其中一个负责连接,允许另一个继续。

当您使用LOCK TABLES时,您不允许数据库引擎执行死锁检测,因此死锁会一直存在,直到您手动进入并终止其中一个死锁进程。更糟糕的是,LOCK TABLES也可以防止读取,并且可以轻松地使整个应用程序戛然而止。

停止使用LOCK TABLES

开始在需要事务完整性的代码区域中使用事务。 在任何地方添加它们。

如果您收到死锁,很可能您有不同的代码路径,以不同的顺序对相关的数据位执行相关操作,您没有在正确的位置使用事务。

还有其他选择。一种是设计数据库例程,以便它们检测何时发生死锁,并开始重新播放所需的事件,以便再次进行。换句话说,您将回滚,重新启动事务,并尝试再次执行相同的操作。有可能导致死锁的条件已经解决,所以你可能没问题。不幸的是,死锁中涉及的其他进程可能已经改变了您正在使用的一些数据,因此重新启动可能有点复杂。

最后,另一种选择是根本不使用事务或锁。你不是在处理钱,是吗?看起来你正在处理用户和评级。这是非常简单的数据。没有人会关心或注意到当前评级是否缺少在有人做了导致重新计算评级的事情之后立即注册的投票。