5

我有一个 mysql 触发器,我担心几天前将触发器部署到我的生产站点后注意到我的数据库中有一些“未同步”的数据。

为了在此处发布,我已经简化了我的代码。

有3张表:

分数表:ID、UserID、Score、GameID(用户每次玩游戏输入一个分数,可以多次玩同一个游戏)

score_summary表:ID、UserID、GameID、SummaryValue(此表保存每个用户每场比赛的跑分)

game_summary表:ID、GameID、SummaryValue(此表保存每场比赛的跑分总分)

当将用户的游戏得分输入到得分表中时,触发器用于更新表 score_summary 中的用户运行总得分 (SummaryValue) 并更新给定 GameID 的 game_summary 表。

CREATE TRIGGER scores_insert_trigger AFTER INSERT ON scores
FOR EACH ROW BEGIN

    UPDATE scores_summary
    SET SummaryValue=SummaryValue + NEW.Score 
    WHERE UserID=NEW.UserID
    SELECT ROW_COUNT() INTO rowCount;
    IF (rowCount=0) THEN
        INSERT INTO scores_summary
        (UserID, GameID, SummaryValue)
        VALUES
        (NEW.UserID, NEW.GameID, NEW.Score);
    END IF;

    UPDATE game_summary
    SET SummaryValue=SummaryValue + NEW.Score 
    WHERE GameID=NEW.GameID
    SELECT ROW_COUNT() INTO rowCount;
    IF (rowCount=0) THEN
        INSERT INTO game_summary
        (GameID, SummaryValue)
        VALUES
        (NEW.GameID, NEW.Score);
    END IF;
END;

我担心如果多个用户同时输入分数,触发器会进入竞争条件 - 特别是当特定游戏不存在分数时更新 game_summary - 如果两个用户同时尝试此操作时间,他们都会得到 rowCount=0,然后都会进行插入?

我的担忧是否合理,如果是,我能做些什么吗?

提前谢谢各位。

4

2 回答 2

1

只需创建UNIQUE索引game_summary.GameID或使其成为主键。

UNIQUEindex 将防止第二个用户添加重复的行。整个事务将失败并被回滚,因此您的应用程序需要处理此异常,例如在失败后在放弃之前重试。此解决方案的缺点是在非常繁忙的环境中,这将导致许多冲突和许多回滚,但您可以确定不会有任何重复的行。

您还可以使用GET_LOCK(str, timeout)函数来获得给定的排他锁GameID,更新或插入值,最后是RELEASE_LOCK(str)以便下一个用户也可以更新分数。在某些情况下,这可能会更有效,但您需要检查一下。

于 2012-12-14T17:16:09.043 回答
0

我想为我的特殊情况提供一个答案。

我的更新语句是原子更新,这意味着 mysql 引擎可以处理任何潜在的竞争条件。

为了避免插入时出现竞争条件,我选择了 ON DUPLICATE KEY UPDATE,这将再次是原子的,并且将避免两个或多个线程导致创建多行。

谢谢你的帮助。

于 2013-01-04T00:12:00.733 回答