在我正在开发的应用程序中,我有潜在的竞争条件,我希望在我的查询中考虑并避免。
总结申请流程......
在entries
表中创建一个新行:
INSERT INTO entries ( name, email ) VALUES ( 'Foo Bar', 'foo@example.com' );
通过查看时间敏感的prizes
表,了解Bar先生是否是赢家:
SELECT id FROM prizes WHERE various_time_conditions = 'met' AND id NOT IN ( SELECT prize_id FROM entries );
如果他是胜利者,请相应更新他的输入行:
UPDATE entries SET prize_id = [prize id] WHERE id = [entry id];
由于每个奖项只能发出一次,我需要消除任何竞争条件的可能性,其中另一个进程可以查询奖品表并更新上述步骤2和3之间的条目表。
我一直在做一些研究,发现了很多关于交易的信息(我所有的表都使用InnoDB)和使用MySQL的SELECT ... FOR UPDATE
语法,但我对此感到困惑。这对我来说是最合适的解决方案。
答案 0 :(得分:4)
您将要锁定奖品记录。因此,如果您不打算使用像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
没有FOR UPDATE
不要等待锁定。