LockModeType Jpa

时间:2015-10-11 07:35:24

标签: oracle hibernate jpa concurrency transactions

我对JPA中LockModeTypes的工作感到困惑:

  1. LockModeType.Optimistic

    • 在提交时递增版本。
    • 这里的问题是:如果我的实体中有版本列,如果我没有指定此锁定模式,那么它的工作原理是什么呢?
  2. LockModeType.OPTIMISTIC_FORCE_INCREMENT

    • 此处,即使实体未更新,它也会增加版本列。
    • 但是如果在提交此事务之前任何其他进程更新了同一行,它的用途是什么?这笔交易无论如何都会失败。那么这个LockModeType的用途是什么。
  3. LockModeType.PESSIMISTIC_READ

    • 此锁定模式发出select for update nowait(如果未指定提示超时)..
    • 所以基本上这意味着在提交此事务之前没有其他事务可以更新此行,那么它基本上是一个写锁,为什么它被命名为Read锁?
  4. LockModeType.PESSIMISTIC_WRITE

    • 此锁定模式还会发出select for update nowait(如果未指定提示超时)。
    • 这里的问题是这个锁定模式和LockModeType.PESSIMISTIC_READ之间有什么区别,因为我看到它们同时触发相同的查询?
  5. LockModeType.PESSIMISTIC_FORCE_INCREMENT

    • 这会select for update nowait(如果没有指定提示超时)并且还会增加版本号。
    • 我完全没有使用它。
    • 如果for update no wait存在,为什么需要增加版本?

1 个答案:

答案 0 :(得分:22)

我首先要区分乐观锁和悲观锁,因为它们的底层机制不同。

乐观锁定完全由JPA控制,只需要DB表中的其他版本列。它完全独立于用于存储关系数据的底层数据库引擎。

另一方面,悲观锁定使用底层数据库提供的锁定机制来锁定表中的现有记录。 JPA需要知道如何触发这些锁,而某些数据库不支持它们或仅部分支持它们。

现在到锁类型列表:

  1. LockModeType.Optimistic

    • 这是默认值。它通常被忽略,如ObjectDB所述。在我看来它只存在,所以你可以动态计算锁定模式并进一步传递它,即使锁最终会是OPTIMISTIC。虽然不是很可能的用例,但提供一个引用甚至是默认值的选项总是很好的API设计。
    • 示例:

      LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);

  2. LockModeType.OPTIMISTIC_FORCE_INCREMENT

    • 这是一个很少使用的选项。但是如果你想锁定另一个实体引用这个实体,这可能是合理的。换句话说,即使未修改实体,您也希望锁定实体,但可能会修改与此实体相关的其他实体。
    • 示例:我们有实体书和书架。可以添加Book to Shelf,但book没有任何对其书架的引用。锁定将书籍移动到书架的动作是合理的,这样在本交易结束之前书籍不会在另一个书架(由于另一个交易)结束。要锁定此操作,仅锁定当前书架实体是不够的,因为该书不必在书架上。锁定所有目标书架也没有意义,因为它们在不同的交易中可能会有所不同。唯一有意义的是锁定图书实体本身,即使在我们的情况下它没有被改变(它没有引用它的书架)。
  3. LockModeType.PESSIMISTIC_READ

    • 此模式类似于LockModeType.PESSIMISTIC_WRITE,但在一件事情上有所不同:直到某个事务对同一实体执行写锁定,它不应阻止读取实体。它还允许使用LockModeType.PESSIMISTIC_READ锁定其他事务。 WRITE和READ锁之间的区别很好地解释了here (ObjectDB)here (OpenJPA)
  4. LockModeType.PESSIMISTIC_WRITE

    • 这是LockModeType.PESSIMISTIC_READ的更强版本。当WRITE锁定到位时,JPA在数据库的帮助下将阻止任何其他事务读取实体,而不是像READ锁一样写。
    • 没有规定如何在JPA提供商中与底层DB合作实现这一点。对于Oracle的情况,我会说Oracle没有提供接近READ锁的东西。 SELECT...FOR UPDATE实际上是一个WRITE锁。它可能是休眠中的一个错误,或者仅仅是一个决定,而不是实现自定义的“更软”READ锁定,而是使用“更难”WRITE锁。这主要不会破坏一致性,但不会保留所有带READ锁的规则。您可以使用READ锁和长时间运行的事务运行一些简单的测试,以确定是否有更多事务能够在同一实体上获取READ锁。这应该是可能的,而不是WRITE锁。
  5. LockModeType.PESSIMISTIC_FORCE_INCREMENT

    • 这是另一种很少使用的锁定模式。但是,您可以选择合并PESSIMISTICOPTIMISTIC机制。在以下场景中使用普通PESSIMISTIC_WRITE会失败:
      1. 事务A使用乐观锁定并读取实体E
      2. 事务B获取实体E上的WRITE锁定
      3. 事务B提交并释放E的锁定
      4. 事务A更新E并提交
    • 在步骤4中,如果版本列没有被事务B递增,则没有任何东西阻止A覆盖B的更改。锁定模式LockModeType.PESSIMISTIC_FORCE_INCREMENT将强制事务B更新版本号并导致事务A失败并{{1} 1}},即使B使用悲观锁定。