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

标签 mysql database postgresql concurrency transactions

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

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

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

  1. 爱丽丝想玩,点击“搜索按钮”。
  2. 假设此时没有任何游戏,将在games 中添加一个新行(使用src_user FK 给Alice,以及dst_user FK 到 NULL)。
  3. 然后,Bob 来了,点击“搜索按钮”。
  4. 此刻,有 Alice 的游戏请求,因此 Bob 可以加入。 dst_user FK 然后可以从 NULL 切换到 Bob。

这个系统看起来不错。但我担心的是,由于用户数量庞大,如果搜索和更新都不是原子的,可能会有一些同步更新。

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

为了防止这种情况,是否可以在一个查询中处理所有这些(尽可能保持与 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)
);

最佳答案

我会使用这样的查询:

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

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

关于mysql - 原子读取和条件创建或更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32936749/

相关文章:

mysql - 替换 MySql 中的格式化字符串

SQL - 根据条件插入多行基于一条记录

java - 如何处理来自外部源的分解 unicode 并将其存储在 postgresql 中

Python-PostgreSQL psycopg2 接口(interface) --> executemany

PHP 只打印一行

php - 未选择数据库。预约类(class)录入失败: No database selected

MySQL 使用 group by 从临时插入

android - SQLite - 是否可以通过插入语句插入 BLOB?

sql-server - Azure SQL 数据库的事务单位是什么

sql - Postgres 并发性和可串行化。我需要 SERIALIZABLE 隔离级别吗?