java - 在这种并发情况下如何保证数据的一致性?

标签 java mysql concurrency data-consistency

问题是这样的:

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

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

我正在使用 MySQL 和 Java。

谢谢

最佳答案

假设名称列上有一个唯一约束,每个insert 都会获取一个锁。任何试图同时插入它的线程都将等待,直到第一次 insert 成功或失败(tx 提交或回滚)。

如果第一笔交易成功,第二笔交易将因违反唯一键而失败。然后你就知道它已经存在了。

如果每个事务有一个插入,那没问题。如果每个事务有超过 1 个插入,则可能会死锁。

Each thread will pass a String name - where that name exists in the table, the database should return the id for the row, where the name doesn't already exist, the name should be inserted and the id returned.

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

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 中的错误量。

关于java - 在这种并发情况下如何保证数据的一致性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2432879/

相关文章:

java - 错误: no enclosing instance of type BPN is in scope {

java - 在 Java 中调用 wait() 时,所有 Swing 框架都得到 "frozen"

java - 每个租户的 Hibernate 数据库 Multi-Tenancy 连接提供程序正在为单个租户创建多个数据库连接

java - 通过 java 套接字与 c 服务器的套接字

java - 从数据库中检索 java 中的完整日期

mysql - 如何使用 native 同步函数从 Amazon Aurora MySQL 数据库集群调用 Lambda 函数

php - mysql_real_escape_string() 说用户访问被拒绝 'drrifae' @'localhost'

php - 部署 WAMP -> 实时站点 - 任何随机提示?

rust - 如何在Rust中创建单线程单例?

Java 并发读/写