【问题标题】:MySQL InnoDB locking only the affected rows?MySQL InnoDB 仅锁定受影响的行?
【发布时间】:2009-10-19 19:35:13
【问题描述】:

我有一个包含用户的 InnoDB 表,如下所示:

+--------------+-----------------------+
| user_id      | name                  |
+--------------+-----------------------+
| 1            | Bob                   |
| 1            | Marry                 |
| 2            | Bob                   |
| 1            | John                  |
| 3            | Bob                   |
| 2            | Marry                 |
+--------------+-----------------------+

在每次插入时,我都会将 user_id 增加 1,例如,Bob 的下一个 user_id 将是 4

我使用这个查询来做到这一点:

INSERT INTO users (user_id, name)
SELECT 1 + coalesce((SELECT max(user_id) FROM users WHERE name='Bob'), 0), 'Bob';

现在我需要确保两个不同的用户不会同时添加“Bob”。我不想要任何两个用户 ID 为 4 的 Bob。每个 Bob 的用户 ID 必须不同。

是否可以在运行上述插入查询时写入和更新锁定 Bob 的所有行?我无法锁定整个表,因为许多其他用户仍然需要完全访问他们的行。此外,所有行都应始终可读。我该怎么做?

【问题讨论】:

    标签: sql mysql innodb rowlocking


    【解决方案1】:

    要解决您问题的第一部分, 在 user_id 和 name 上创建唯一索引。

    alter table `users` add unique index ak_user_id_name(user_id,name);
    

    这将防止重复的 user_id,name 记录。

    【讨论】:

    • 但 user_id 行中可以有多个 1,但每个都属于不同的用户。就像可以有多个 Bob,但每个都有不同的 user_id
    • 这不会阻止这一点。它是由 user_id 和 name 组成的复合键。它可以防止输入重复的 user_id/name 组合。所以 1/bob、1/sue、2/bob 都可以。再放入 1/bob 会导致数据库错误。
    【解决方案2】:

    这个问题的答案和this one一样。 InnoDB 将在此处锁定比您预期的基于语句的二进制日志记录更多的行。

    解决方案:使用基于行的二进制日志和已提交读隔离级别。

    【讨论】:

      【解决方案3】:

      假设这里是 InnoDB,您可以在选择行时使用SELECT ... LOCK IN SHARE MODE 锁定行。

      【讨论】:

      • AFAIK LOCK IN SHARED MODE 是不够的,你必须 {{LOCK TABLE}} 或创建一个 uniq 索引,如果它作为@txyoji 回答失败,则重试更新。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-03
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多