【问题标题】:Spring Data/Hibernate MS SQL Server unique constraint and race conditionSpring Data/Hibernate MS SQL Server 唯一约束和竞争条件
【发布时间】:2018-03-19 00:12:40
【问题描述】:

前段时间我遇到了竞争条件问题,当 2 个单独的事务尝试同时检查记录是否存在(通过 4 个字段),如果不存在 - 创建一个新的。

我的环境:

MS SQL Server, Spring Data/JPA/Hibernate

这是重复记录问题。我实现了模拟并发调用的测试,因此能够(在 99.99% 的执行时间相当稳定)重现此问题。

现在我通过对这 4 个字段应用唯一约束来解决此问题。目前我的测试无法重现此问题。我对它真的很满意,但老实说,我并不完全理解它是如何工作的。这正是我创建这个问题的原因——我不明白为什么我的测试没有失败并出现ConstraintViolationException,而两个并发事务同时检查记录的存在,然后尝试创建它(每个) .根据我的测试,我的理解是 - 两个事务同时工作,并且在第一次检查期间不应该找到任何记录。之后,他们应该尝试创建新记录,其中一个事务应该能够做到,而另一个事务应该失败并显示ConstraintViolationException。但是代码运行良好,一切正常,没有任何异常。

在 Spring Data/JPA/Hibernate 级别甚至 MS SQL Server 是否有任何内部同步机制可以防止并发事务不正确工作并允许它们彼此等待工作结果?请解释。谢谢!

【问题讨论】:

    标签: sql-server hibernate jpa transactions spring-transactions


    【解决方案1】:

    简答

    这完全取决于您在表上的索引以及您的查询当时使用的索引。如果不同的进程使用不同的执行计划来检查行是否不存在,那么由于 SQL Server 发出资源锁的方式,它们都将返回 true 并添加一条记录。

    来自 [1]:

    1. 执行写操作时,SQL Server 不锁定相关 索引...,只有相关的数据行。
    2. 执行读取操作时,SQL Server 仅锁定它在其中找到并使用的对象(例如索引、数据行等) 它的访问路径。

    通过在这 4 个字段上添加唯一约束,您隐式有效地添加了覆盖索引,这导致您的所有进程使用相同的查询计划,因此在相同对象上以相同的顺序获取资源锁。

    长答案

    Data mismatch when querying with different indexes

    有关资源锁定的详细信息,请阅读以下内容: [1]https://www.mssqltips.com/sqlservertip/1485/using-sql-server-indexes-to-bypass-locks/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 2018-07-25
      • 2020-09-14
      • 2010-10-30
      • 2017-10-07
      相关资源
      最近更新 更多