一尘不染

如何避免MySQL中的竞争条件

sql

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

总结应用程序流程…

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

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

  1. 通过查看对时间敏感的prizes表格,找出Bar先生是否是获胜者:

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

  1. 如果他是赢家,请相应地更新他的条目行:

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

由于每个奖项只能颁发一次,因此我需要消除比赛条件的任何可能性,在这种情况下,另一个过程可以查询奖项表并更新上述步骤2和3之间的条目表。

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


阅读 266

收藏
2021-03-10

共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到查询中,因为SELECT没有的a不会FOR UPDATE等待锁定。

2021-03-10