【问题标题】:How to prevent selection of the row while it is being handled?如何防止在处理行时选择行?
【发布时间】:2023-04-07 00:35:01
【问题描述】:

我有 MySQL (InnoDB) 表,其列 is_locked 显示记录的当前状态(系统现在是否正在处理它)。

另一方面,我有许多节点执行SELECT * FROM table_name WHERE is_locked = 0,然后处理从该表中获取的行。

在我的代码中我这样做:

  1. 系统从 DB (SELECT * FROM table_name WHERE is_locked = 0) 获取行
  2. 系统通过命令UPDATE table_name SET is_locked = 1 WHERE id = <id>锁定行

问题: 节点工作速度非常快,所有节点都可能获得相同的行,然后它们中的第一个将更新该行并将is_locked 设置为 1

我发现了 LOCKING 表,但我认为这不是正确的方法。 谁能告诉我,如何处理这种情况?

【问题讨论】:

  • 您可以锁定 InnoDB 中的单个行。
  • 自己存储锁定是一个根本性的错误想法。如果您编写脚本崩溃并烧毁并锁定该行,会发生什么情况。它将被锁定,您无法知道某个进程是否正在使用它。
  • >自己存储锁定是一个根本有缺陷的想法。如果您编写脚本崩溃并烧毁并锁定该行,会发生什么情况。它将被锁定,您无法知道进程是否正在使用它。 – 你说得对,这就是我在这里问你的原因:)
  • 至少 a),限制您的选择和 b) 在您的更新中包含 WHERE is_locked=0 and id = blah,这样只有一次更新尝试会成功。检查返回值,如果更新影响了 0 行,您的节点没有获得该锁/不应该处理。所有这一切最好在一个存储过程中完成,首先更新一行,然后返回它更新的那一行,而不是先选择,稍后更新

标签: php mysql sql


【解决方案1】:

我推荐两件事:

  • 将您的选择限制为一个,因为您正在处理并发问题,最好在每次迭代中采取较小的“咬”

  • 使用事务,这允许您启动事务、获取记录、锁定它然后提交事务。这将强制 mysql 强制执行并发锁。

【讨论】:

  • 交易没有成功。更新后我确实提交了,所有其他节点都得到了以前的结果。奇怪。
  • 您能告诉我您是如何进行交易的吗?也许包括一个 gist/pastebin 链接以包含 php。
  • 我已经使用了上面的解决方案。先更新行,再通过ID获取。这是完美的工作。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-19
  • 2011-08-29
  • 1970-01-01
  • 2021-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多