我正在竞赛网站上工作,其中抽奖逻辑相当简单:每220个参赛作品应该是胜利者。
我在这里简要概述了这个过程:
-- create new entry row
INSERT INTO entries (...) VALUES (...); -- returns 456 as the newly created id
-- get last winner
SELECT id
FROM entries
WHERE winner = 1
ORDER
BY created DESC
LIMIT 1;
-- see how many entries there have been since
SELECT COUNT(*)
FROM entries
WHERE id > 123 -- id selected in last query
AND id <= 456; -- id of newly created entry
-- if count = 220
UPDATE entries
SET winner = 1
WHERE id = 456;
上述逻辑没有考虑竞争条件的可能性。我需要使用什么样的锁定来防止竞争条件发生?
(我正在使用MySQL / InnoDB。)
答案 0 :(得分:1)
假设您使用的是某种编程语言,这里有一些伪代码:
$last = SELECT MAX(id) FROM tbl WHERE winner=1;
UPDATE tbl SET winner=1 WHERE id > $last LIMIT 1 OFFSET 220;
没有竞争条件,因为UPDATE在最坏的情况下会设置winner
。
每次输入行时,您是否正在执行此代码?这可以变成TRIGGER并避免更新。相反,它会根据NEW.winner = 1
设置SELECT
。
相反,如果你是在定期进行,那么你需要重复代码序列,直到它不再更新任何行(rows_affected())。这可以允许自上次更新以来的2 * 220名参赛者。您可以将代码转换为存储过程。
最好有
INDEX(winner, id)