原子读取和条件创建或更新

时间:2015-10-04 18:16:50

标签: mysql database postgresql concurrency transactions

我想在一个事务请求中执行对数据库进行读取和条件创建或更新。

让我们以暴雪的星际争霸游戏为例: 假设Bob想要与其他随机玩家进行决斗。 他只需点击“搜索按钮”,然后在查询其数据库后,服务器将创建一个与Bob相比较的新游戏,例如Alice。

在此示例中,假设数据库包含usersgames个表。 这种情况可能发生在以下步骤:

  1. Alice想玩,然后点击“搜索按钮”。
  2. 假设此时没有任何游戏,我们会在gamessrc_user FK添加到Alice,dst_user FK到NULL)添加新行。
  3. 然后,鲍勃来了,然后点击“搜索按钮”。
  4. 此时,有Alice的游戏请求,所以Bob可以加入。然后,dst_user FK可以从NULL切换到Bob。
  5. 这个系统似乎很好。但我担心的是,由于用户数量庞大,如果搜索和更新都不是原子的,可能会同时进行更新。

    我的意思是,如果同时Bob和Oscar正在寻找游戏,那么SQL服务器首先会为两个用户回答Alice的游戏请求(这是games表中的一行)。然后,鲍勃和奥斯卡都会尝试更新这条线以加入游戏。

    为了防止这种情况,是否可以在一个查询中处理所有这些(如果可能的话,保持与MySQL和PostgreSQL的兼容性)?

    PS:数据库结构可能就是这个......

    CREATE TABLE users (
      id SERIAL PRIMARY KEY,
    );
    
    CREATE TABLE games (
      id                        SERIAL              PRIMARY KEY,
    
      src_user_id               BIGINT UNSIGNED     NOT NULL,
    
      -- if NULL, the game is not ready...
      dst_user_id               BIGINT UNSIGNED         NULL,
    
      FOREIGN KEY (src_user_id) REFERENCES users(id),
      FOREIGN KEY (dst_user_id) REFERENCES users(id)
    );
    

1 个答案:

答案 0 :(得分:1)

我使用这样的查询:

update games set dst_user_id=? where id=? and dst_user_id is null;

这样我可以确保只有在没有其他用户加入时才会更新行。要检查游戏是否成功创建,我要检查更新的行数 - 大多数数据库引擎都支持此行。