【问题标题】:Multiple processes updating same rows results in deadlock in mysql?多个进程更新相同的行会导致 mysql 死锁?
【发布时间】:2014-10-30 12:03:50
【问题描述】:

我正在开发一个 php 程序,该程序会多次分叉,从而产生几个工作进程,然后这些工作进程会自动处理一个任务表。每个进程打开它自己的 mysql 连接(这是必须的,因为 php 的分叉架构),然后应该处理它自己的任务(没有两个工作人员应该处理同一个任务)。为此,工人在开始处理之前“接受”一项任务。这是通过以下方式实现的:

  1. 工作人员请求任务
  2. 一个事务被启动,所有“挂起”的任务都被查询
  3. 这些任务是重复的。然后脚本尝试通过更新它的状态来“接受”每个任务。更新有一个条件where status = 'pending',以确保它在此期间未被使用。
  4. 一旦成功“接受”任务,迭代就会停止并提交事务。

我首先在 mysql shell 中测试了这个场景——在两个终端窗口中建立了两个到数据库的连接。双方开始交易。然后在第一个窗口中将任务更新为“采取”。尝试在第二个窗口中更新相同的任务。然后第二个窗口一直等到我在第一个窗口中提交事务并且礼貌地失败了(0 行受影响)。

现在,在 php(使用 PDO)中,一旦第二个进程尝试执行任务,我就会在 db 上遇到死锁:

PHP 致命错误:未捕获异常 'PDOException' 并带有消息 'SQLSTATE[40001]:序列化失败:尝试获取锁时发现 1213 死锁;尝试在 ...中重新启动事务'

我不确定我是否应该只将实际的更新任务以采取包装在事务中。但在我看来,我在程序中执行的方式与我在 shell 上执行的方式相同,因此应该可以工作。

有人可以帮我解决我在这里缺少的东西吗?

【问题讨论】:

  • 您的任务表的类型是什么:'MyISAM' 或 'InnoDB'?在您的情况下,必须设置“InnoDB”
  • 死锁并不可怕,它们很正常。处理此类问题的通常方法是重新启动事务。您可以跟踪由于死锁而失败的次数,然后停止尝试。该任务将不完整,最终将由另一个工人接手。
  • @NB:你的意思是它基本上是 mysql 说“嘿,自从你开始交易以来,另一个进程已经更新了这一行”?。我将如何重新开始交易?
  • @HalayemAnis:是的 InnoDB。
  • 我原以为死锁很少见,只要:您在“工作任务”中使用事务并以相同的顺序访问资源(表)。您可能会遇到“超时”。

标签: php mysql fork deadlock mariadb


【解决方案1】:

你在 InnoDB 中,这很好。

您的任务是否在表格中?我想他们是,但你没有说得这么明确。

试试这门学科,抓住要完成的任务。

BEGIN;   /* start a transaction */
SELECT task_id, whatever
  FROM tasktable
 WHERE status = 'pending'
 LIMIT 1
FOR UPDATE;

然后,如果您收到带有任务 ID 的行,则您已准备好处理该任务。如果您没有返回任何行,则没有任何待处理的任务。

将任务标记为工作。

UPDATE tasktable 
   SET status = 'working' 
 WHERE task_id = <<the task ID you just got back>>;

那么,

COMMIT;

如果您遇到死锁异常(您可能仍会遇到一个,但会更罕见),然后发出 ROLLBACK;,然后再次尝试整个序列。

然后,做任务。完成后将其标记为已完成。您不需要为此进行交易,因为您可以在一个查询中完成。

UPDATE tasktable 
   SET status = 'complete' 
 WHERE task_id = <<the task ID you just got back>>;

如果您在客户端连接中关闭了自动提交,请不要​​忘记在查询后提交。

【讨论】:

  • 感谢您的回复,这几乎就是我正在做的事情并且遇到了问题。
【解决方案2】:

我找到了"solution" that I'm going with。如果有人有不同的解决方案,我很乐意听到它,如果我最终使用它,我很乐意接受你的回答。

所以基本上是尝试在循环中“执行”一项任务,当我遇到死锁时,我会回滚并重试。我的第一个测试表明,当所有工人都试图完成一项任务时,它可以解决最初的问题。

【讨论】:

    猜你喜欢
    • 2021-11-27
    • 2020-08-29
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    相关资源
    最近更新 更多