我有时得到mysql死锁错误说:
'获取锁时发现死锁;尝试重新启动事务'
我有一个队列表,其中多个php进程同时运行从表中选择行。然而,对于每个进程,我希望它每次抓取一个唯一的批处理行,所以我没有任何重叠的行被选中。
所以我运行这个查询:(这是查询我得到死锁错误)
$this->db->query("START TRANSACTION;");
$sql = " SELECT mailer_queue_id
FROM mailer_queues
WHERE process_id IS NULL
LIMIT 250
FOR UPDATE;";
...
$sql = "UPDATE mailer_queues
SET process_id = 33044,
status = 'COMPLETED'
WHERE mailer_queue_id
IN (1,2,3...);";
...
if($this->db->affected_rows() > 0) {
$this->db->query("COMMIT;");
} else{
$this->db->query("ROLLBACK;");
}
我也是:
同时向表中插入行(没有事务/锁)
同时更新表中的行(没有事务/锁)
同时从表中删除(没有事务/锁)
同样,我的更新和删除只更新和删除行,他们有一个process_id分配给他们…我在哪里执行我的事务,"SELECT行…其中process_id = null。从理论上讲,它们不应该重叠。
我想知道是否有一种合适的方法来避免这些死锁?
是否会发生死锁,因为一个事务在选择/更新时锁表时间过长,而另一个进程试图执行相同的事务并超时?
任何帮助都非常感谢
当两个或多个进程以被锁的资源重叠的方式请求锁时,就会发生死锁,但是发生的顺序不同,因此每个进程都在等待另一个进程锁定的资源,而另一个进程正在等待原始进程打开的锁。
在现实世界中,考虑一个建筑工地:你有一个螺丝刀和一个螺丝。两个工人需要装进一个螺丝。工人1抓起螺丝刀,工人2抓起螺丝。工人1也想去抓螺丝,但是抓不到,因为螺丝被工人2抓住了。工人2需要螺丝刀,但拿不到,因为工人1拿着它。所以现在他们陷入僵局,无法继续,因为他们只得到了他们需要的两种资源中的一种,而他们都不会礼貌地"退后一步"。
如果发生了事务外的更改,可能会有一个(或多个)更新/删除与事务内保留的锁定区域重叠。
您可能希望在开始事务之前尝试LOCK TABLES,从而确保您对表具有显式控制。该锁将等待,直到特定表上的所有活动完成。
我想网上的每个人都很好地解释了死锁。Mysql提供了非常好的日志来检查最近发生的所有死锁和哪个当时的查询被卡住了。检查这个mysql文档页面并搜索LATEST DETECTED DEADLOCK
这是一个伟大的日志,帮助发现许多微妙的死锁