修改同一行的多个查询

时间:2011-04-19 17:08:32

标签: mysql database database-design

我正在创建一个游戏,其中玩家可以挑战存储在数据库中的随机玩家。这就是我这样做的方式:( MySQL数据库)

当用户搜索随机用户时,如果没有用户等待,我将用户的'waiting'属性设置为1.

如果已经有用户在等待挑战(“等待”已经设置为1),我将它们匹配在一起并将其“等待”属性设置为0.(基本上,我在数据库表中查询任何用户'waiting'属性设置为1。)

我想我的第一个问题是,这是一个好主意吗?我关心的是同步。如果两个用户同时查询等待的玩家,那么等待的用户将被挑战两次。虽然选择查询和更新查询之间的时间范围非常小,但这在技术上是可行的,对吗?

有没有办法避免这种情况?或者这是我不应该担心的事情?

3 个答案:

答案 0 :(得分:1)

你想要做的是创造某种互斥情况。基本上,您需要让查询增加一些数字,然后测试它是否是正确的值。

SELECT *
FROM players
WHERE ready = 1
AND connections = 0

然后你需要有一个增量

UPDATE players
SET connections = connections + 1
WHERE id IN (...)

然后你应该检查连接号码是否仍然是一个(其他人挑战同一个玩家)

SELECT *
FROM players
WHERE connections = 1
AND id IN (...)

你还需要重置两次受到挑战的人

UPDATE players
SET connections = 0
WHERE connection > 1

答案 1 :(得分:1)

如果您在找到两个想要匹配的玩家的同时更新“等待”标志,则任何其他查询都会看到该更新。 (这可能应该在存储过程中完成,以减少您正在搜索等待播放器的查询之间的时间,然后更新它们的状态。)如果两个查询尝试并在完全改变同一行同时,其中一个将失败,因为该行应该被锁定以进行更新。

我不确定MySQL是否会产生死锁异常。

确保您的客户端应用中有很好的异常处理。如果从此操作中获得异常指示更新失败,请再试一次。您可能希望生成一个有意引起您担心的情况的测试,并验证您的修复是否按预期工作。

我期望这种情况发生的唯一方法是,如果您使用参数化查询并且必须执行单独的查询以查找匹配,然后更新“等待”标志。使用存储过程,在服务器上一次完成所有操作,并享受更高的稳定性和安宁。

答案 2 :(得分:1)

你对并发部分是正确的。两个人可以挑战同一个用户并直到挑战部分。

一种可能的方法是锁定行以进行更新,同时运行的另一个会话将无法锁定相同的用户ID。

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

相反,您可以尝试第三个表,其中包含两个用户的ID,如下所示。?

create table users(
   id number,
   name varchar2(200)
);

create table challenge(
   id1 number,
   id2 number,
   constraint pk1 primary key (id1,id2),
   constraint fk1 fk_id1 references users(id1),
   constraint fk2 fk_id2 references users(id),
   );

如果你想展示没有挑战的用户......你所要做的就是......

select * from users where id not in (
 select id1 from challenge
   union
 select id2 from challenge);

主键会阻止已经参与challlenge的用户再次添加到另一个用户。