Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在这种并发情况下,如何确保数据一致性?_Java_Mysql_Concurrency_Data Consistency - Fatal编程技术网

Java 在这种并发情况下,如何确保数据一致性?

Java 在这种并发情况下,如何确保数据一致性?,java,mysql,concurrency,data-consistency,Java,Mysql,Concurrency,Data Consistency,问题是: 我有多个相互竞争的线程(100+)需要访问一个数据库表 每个线程将传递一个字符串名称——如果表中存在该名称,则数据库应返回该行的id,如果该名称不存在,则应插入该名称并返回id 数据库中只能有一个name实例,即名称必须唯一 如何确保线程1不会在线程2尝试插入name1的同时插入name1?换句话说,如何保证并发环境中name的唯一性?这也需要尽可能的高效——这有可能成为一个严重的瓶颈 我正在使用MySQL和Java 感谢对数据库中的“名称”列创建唯一约束。为“名称”列添加唯一约束

问题是:

  • 我有多个相互竞争的线程(100+)需要访问一个数据库表
  • 每个线程将传递一个
    字符串名称
    ——如果表中存在该名称,则数据库应返回该行的id,如果该名称不存在,则应插入该名称并返回id
  • 数据库中只能有一个
    name
    实例,即名称必须唯一
如何确保线程1不会在线程2尝试插入
name1
的同时插入
name1
?换句话说,如何保证并发环境中
name
的唯一性?这也需要尽可能的高效——这有可能成为一个严重的瓶颈

我正在使用MySQL和Java


感谢对数据库中的“名称”列创建唯一约束。

为“名称”列添加唯一约束。

假设“名称”列上存在唯一约束,则每次插入都将获得一个锁。任何试图第二次同时插入它的线程都将等待第一次插入成功或失败(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
由于唯一索引上可能存在高争用,因此
插入
可能会阻塞一段时间。在这种情况下,事务可能会超时。进行一些压力测试,并调整配置,直到它与您的负载正常工作

此外,您还应该检查是否得到了唯一约束冲突异常或其他异常

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



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

Plus可从异常中正确检测唯一约束问题。这可能非常重要,具体取决于JDBC驱动程序在异常中返回的信息。Spring在其JDBC模块中实现了这一点,因此,如果您陷入困境,请偷偷看一看代码。谢谢,回答得很好-还有一件事,我可以在sql中检测到唯一的约束异常吗?或者我必须让它在java中被检测到吗?哦,还有另一个问题-我认为mysql将缓存查询结果,所以理论上如果一个名称已经被插入并返回一次,我应该能够利用缓存返回存在的名称吗?对不起,还有一个问题——我假设您上面概述的算法都可以在sql中完成,但是我是否需要手动管理表锁,或者mysql会为我这样做?谢谢你的建议:)我曾经用JDBC检查异常的类型。它是特定于数据库的,您需要检查异常中的错误代码(SQLException#getErrorCode)。我知道Oracle的ORA-0001,但不知道MySQL的代码。只要产生错误,你就会得到它。虽然我从来没有这样做过,但我想你也可以检查存储过程中的错误,如果这是你的意思的话(请参阅)。至于其他问题,我不知道MySQL缓存的细节,但这对你来说应该是透明的。如果有适当的索引,则锁由数据库管理。