【问题标题】:Guarantee uniqueness of speciifc values using REPEATABLE READ使用 REPEATABLE READ 保证特定值的唯一性
【发布时间】:2018-11-06 22:28:42
【问题描述】:

我们有一个简单的表格:

Human:
+------+
|Height|
+------+
|      |
+------+

而且我有一个方法可以增加一个人:

@AutoWired 
HumanRepository humanRepo; // JpaRepository

@Transactional(isolationLevel = REPEATABLE_READ)
void addHuman(int height){
    if(humanRepo.existsByHeight(height){
      throw new HumanWithSuchHeightExists();
    }
    humanRepo.save(Human.builder().height(height).build())
}

我想保证只存在一个具有特定身高的人。

  1. REPEATABLE_READ 能保证吗?
  2. 我的代码(伪代码)是否正确满足该条件?

【问题讨论】:

    标签: database spring postgresql isolation-level


    【解决方案1】:

    理论说唯一能够绝对保证的隔离级别。数据完整性(wrt 声明的规则)是 SERIALIZABLE。

    使用 REPEATABLE READ,理论上您仍然面临两个事务尝试插入同一行的风险,并且会出现以下一系列事件:

    T1 检查行存在,行不存在
    T2 检查行存在,行不存在
    T1 插入,可能重复行的存在性检查(仍然不存在)
    T2 插入,可能重复行的存在性检查(仍然“不存在”,因为 T1 尚未提交,因此其新插入的数据对 T2 不可见)。
    T1 提交
    T2 提交

    REPEATABLE READ,顾名思义,只提供关于现有行的保证(即如果发现一行存在,它不会被改变由其他事务和读取然后变为“可重复”)。

    【讨论】:

    • 感谢您的回复。那么,如果我将 REPEATABLE_READ 替换为 SERIALIZABLE 它会起作用吗?
    • 如果是这样就好了……但是这有点取决于您使用的是哪个 DBMS 引擎,以及它的 SERIALIZABLE 语义是否与理论的语义完全相同。谷歌例如对于一篇文章“Oracle 的可序列化不是 SERIALIZABLE”。如果我没记错的话,IBM DB2 也有术语差异,命名理论的 REPEATABLE READ“读取稳定性”和理论的 SERIALIZABLE“可重复读取”(!!!)。因此,如果您想了解最后的细节,您需要对工具链的每个组件(例如 ORM)的行为进行大量检查。
    • 抱歉,我无法知道每个现有引擎的详细程度。 (如果您的问题是特定于 DBMS 的,请按此标记问题。它有助于吸引那些确实了解您所关注的特定引擎的此类信息的人的注意力。)
    【解决方案2】:

    是的,PostgreSQL SERIALIZABLE 应该防止创建多个具有相同高度的记录。它将中止 T1 或 T2。

    我认为该异常将正式称为反依赖循环 (G2)。这是good reference that includes major databases

    另外,为什么不改用unique constraint

    【讨论】:

      猜你喜欢
      • 2021-11-18
      • 2019-12-14
      • 1970-01-01
      • 2013-11-12
      • 1970-01-01
      • 2012-11-15
      • 2017-07-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多