1

假设我有一个存储在 SQL 数据库中的国际象棋游戏,其架构类似于以下架构:

CREATE TABLE chessgames(
    game_id INTEGER,
    move_id INTEGER,
    move char(4)
};

因此,如果正在进行的游戏(game_id 为 0)具有 e4 e5 的移动,那么该表将具有元组 (0, 1, "e4") 和 (0, 2, "e5")。

现在假设客户端试图通过同时发送 move d4 和 Nf3 来破坏数据库。试图处理两个移动并有效地尝试插入元组 (0, 3, "d4") 和 (0, 3, "Nf3"),两者都具有相同的 move_id,从而破坏了 move_id 的唯一性。

确保唯一性的最佳惯用方式是什么?我想到的一种可能性是让我的 C++ 代码包含一个互斥锁列表,每个游戏一个互斥锁。当 d4 这样的移动到达时,C++ 代码为相应游戏锁定互斥锁,运行以下 SQL 查询

SELECT move_id, move FROM chessgames WHERE game_id = 0

为了获取游戏的所有动作(在我给出的示例中,这将是 e4 和 e5),C++ 代码采用这些动作并检查是否没有行已经具有 move_id = 3,然后执行这些动作以构建当前位置所以它可以检查移动 d4 是否有效。如果有效,则运行

INSERT INTO chessgames VALUES (0, 3, "d4")

将移动存储在数据库中,然后释放互斥锁。

这样,如果 Nf3 移动与它的 d4 移动处理同时到达,它将被锁定的互斥锁阻塞,当最终处理 Nf3 时,它将看到 move_id = 3 的行已经存在,它将被忽略。

有没有更好的方法来做到这一点?我的数据库模式对于我正在尝试做的事情是否合理?

4

2 回答 2

2

首先,您应该在 game_id 和 move_id 列上创建一个唯一索引。这样,您可以确保每个游戏在数据库级别上的 move_id 唯一性。

CREATE UNIQUE INDEX U_game_move
ON chessgames
(game_id, move_id);

然后,互斥锁方法很好,但您也可以考虑创建一个触发器来处理 move_id 递增。

于 2012-12-14T09:56:56.047 回答
0

我了解到我需要的是乐观锁定,就像这个 问题的答案一样。

于 2012-12-21T03:39:42.620 回答