2

问题是这样的:

  • 我有多个竞争线程 (100+) 需要访问一个数据库表
  • 每个线程将传递一个String name- 该名称存在于表中,数据库应返回该行的 id,该名称尚不存在,应插入该名称并返回该 id。
  • 数据库中只能有一个实例name- 即。名称必须是唯一的

如何确保线程一不会name1在线程二也尝试插入的同时插入name1?换句话说,我如何保证name并发环境中的唯一性?这也需要尽可能高效——这有可能成为一个严重的瓶颈。

我正在使用 MySQL 和 Java。

谢谢

4

3 回答 3

7

假设 name 列存在唯一约束,每个都insert将获得一个锁。任何尝试同时第二次插入它的线程都将等到第一次insert成功或失败(tx 提交或回滚)。

如果第一笔交易成功,第二笔交易将失败,并出现唯一密钥违规。然后你就知道它已经存在了。

如果每个事务有一个插入,则可以。如果每个事务有超过 1 个插入,您可能会死锁。

每个线程将传递一个字符串名称 - 如果该名称存在于表中,数据库应返回该行的 ID,如果该名称不存在,则应插入该名称并返回该 ID。

总而言之,算法是这样的:

1 read row with name
   2.1 if found, return row id
   2.2 if not found, attempt to insert
      2.2.1 if insert succeeds, return new row id
      2.2.2 if insert fails with unique constraint violation
          2.2.2.1 read row with name
          2.2.2.2 read should succeed this time, so return row id

由于唯一索引可能存在高争用insert,因此可能会阻塞一段时间。在这种情况下,事务可能会超时。进行一些压力测试,并调整配置,直到它与您的负载一起正常工作。

此外,您应该检查是否获得了唯一的约束违规异常或其他异常。

同样,这仅在每个事务有一个插入时才有效,否则可能会死锁


此外,您可以尝试使用“ select * for update”读取步骤 1 中的行。在这种情况下,它会等待并发插入提交或成功。由于索引争用,这可以稍微减少步骤 2.2.2 中的错误量。

于 2010-03-12T13:13:37.700 回答
3

在数据库中的 name 列上创建唯一约束。

于 2010-03-12T13:11:35.520 回答
2

为 name 列添加唯一约束。

于 2010-03-12T13:13:16.973 回答