【问题标题】:How to avoid race condition in MySQL如何避免 MySQL 中的竞争条件
【发布时间】:2014-03-21 14:12:46
【问题描述】:

我正在开发的应用程序中存在潜在的竞争条件,我想在查询中考虑并避免这种情况。

总结应用流程...

  1. entries 表中创建一个新行:

    INSERT INTO entries ( name, email ) VALUES ( 'Foo Bar', 'foo@example.com' );

  2. 通过查看时间敏感的prizes 表了解 Bar 先生是否是赢家:

    SELECT id FROM prizes WHERE various_time_conditions = 'met' AND id NOT IN ( SELECT prize_id FROM entries );

  3. 如果他是赢家,相应地更新他的输入行:

    UPDATE entries SET prize_id = [prize id] WHERE id = [entry id];

由于每个奖品只能发放一次,我需要消除竞争条件的任何可能性,即另一个进程可以在上述第 2 步和第 3 步之间查询奖品表并更新条目表。

我一直在做一些研究,发现了大量有关事务的信息(我所有的表都使用 InnoDB)并使用 MySQL 的 SELECT ... FOR UPDATE 语法,但我不知道哪个是最适合我的解决方案。

【问题讨论】:

  • 将所有查询放在一个事务中以便快速保险。

标签: mysql sql transactions race-condition


【解决方案1】:

您将要锁定奖品记录。因此,如果您不打算使用诸如winner_id 之类的东西,请在奖品表上添加一些可用性标志(可能带有默认值)。像这样的:

SELECT id FROM prizes WHERE ... AND available = 1 FOR UPDATE

如果您确实分配了奖品,请设置可用性:

UPDATE prizes SET available = 0 WHERE id = ...

当然,您需要将其包装在事务中。

确保每次检查是否有奖品,将AND available = 1 FOR UPDATE 添加到查询中,因为没有FOR UPDATESELECT 不会等待锁。

【讨论】:

  • 谢谢,这对我来说听起来很合理。我是否正确假设运行 UPDATE 语句将自动释放 SELECT ... FOR UPDATE 查询授予的锁?
  • @SamHastings,提交或回滚事务会释放锁。执行UPDATE 不会释放锁定,因为您可能希望执行多次更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
相关资源
最近更新 更多