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

  • LockModeType.Optimistic
  • 在提交时增加版本。
  • 这里的问题是:如果我的实体中有版本列,并且如果我未指定此锁定模式,那么它的工作方式也类似,那么它的用途是什么?
  • LockModeType.OPTIMISTIC_FORCE_INCREMENT
  • 在这里,即使未更新实体,它也会增加版本列。
  • ,但是如果在提交此事务之前有任何其他进程在同一行上更新了,它有什么用?无论如何,该交易将失败。那么LockModeType的用途是什么。
  • LockModeType.PESSIMISTIC_READ
  • 此锁定模式发出select for update nowait(如果未指定提示超时)。
  • ,所以基本上这意味着在提交该事务之前,没有其他事务可以更新该行,然后基本上是写锁定,为什么将其命名为Read锁定?
  • LockModeType.PESSIMISTIC_WRITE
  • 此锁定模式还会发出select for update nowait(如果未指定提示超时)。
  • 问题是这种锁定方式和LockModeType.PESSIMISTIC_READ之间有什么区别,因为我看到两者都触发相同的查询?
  • LockModeType.PESSIMISTIC_FORCE_INCREMENT
  • 这会执行select for update nowait(如果未指定提示超时),并且还会增加版本号。
  • 我完全没有使用它。
  • 如果存在for update no wait,为什么需要版本增加?
  • 最佳答案

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

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

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

    现在到锁类型列表:

  • LockModeType.Optimistic
  • 如果实体指定版本字段,则这是默认值。对于没有版本列的实体,不能保证在任何JPA实现中都不能使用这种类型的锁。如ObjectDB所述,通常会忽略此模式。在我看来,它只是存在的,这样您就可以动态地计算锁定模式,即使锁定最终是最优的,也可以进一步传递它。虽然用例不是很可能,但是提供一个甚至引用默认值的选项也是一种很好的API设计。
  • 示例:
    LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);
  • LockModeType.OPTIMISTIC_FORCE_INCREMENT
  • 这是一个很少使用的选项。但是,如果您想锁定另一个实体对这个实体的引用,这可能是合理的。换句话说,即使您未修改某个实体,您也希望锁定该实体的工作,但是其他实体也可能相对于该实体而被修改。
  • 示例:我们有实体Book and Shelf。可以将Book添加到书架中,但是book没有对其书架的引用。锁定将书移动到书架上的操作是合理的,这样一本书在交易结束前不会落在另一个书架中(由于另一笔交易)。要锁定此 Action ,仅锁定当前书架实体是不够的,因为书还不必在书架上。锁定所有目标书架也没有意义,因为它们在不同交易中可能会有所不同。唯一有意义的事情是锁定书本实体本身,即使在我们这种情况下它没有被更改(它不保留对其书架的引用)。
  • LockModeType.PESSIMISTIC_READ
  • 此模式类似于LockModeType.PESSIMISTIC_WRITE,但不同之处在于:在通过某种事务对同一实体进行写锁定之前,它不应阻止对实体的读取。它还允许其他事务使用LockModeType.PESSIMISTIC_READ锁定。 here (ObjectDB)here (OpenJPA)很好地解释了WRITE和READ锁之间的差异。如果一个实体已经被另一个事务锁定,则对其进行任何锁定尝试都会引发异常。可以将此行为修改为在引发异常并回滚事务之前等待一段时间以释放锁。为此,请在引发异常之前指定javax.persistence.lock.timeout提示以及要等待的毫秒数。如Java EE tutorial中所述,有多种方法可以在多个级别上执行此操作。
  • LockModeType.PESSIMISTIC_WRITE
  • 这是LockModeType.PESSIMISTIC_READ的更强版本。当WRITE锁定到位时,JPA在数据库的帮助下将阻止任何其他事务读取实体,而不仅仅是像READ锁定那样进行写入。
  • 没有规定如何在JPA提供程序中与基础DB合作实现此方法。对于Oracle,我会说Oracle不能提供类似于READ锁的功能。 SELECT...FOR UPDATE实际上是WRITE锁。这可能是休眠中的错误,或者是一个决定,它不是使用自定义的“较软”的READ锁,而是使用“较硬”的WRITE锁。这在大多数情况下不会破坏一致性,但是不会保留所有带有READ锁的规则。您可以使用READ锁和长时间运行的事务运行一些简单的测试,以了解是否有更多事务能够在同一实体上获取READ锁。这应该是可能的,但不能使用WRITE锁。
  • LockModeType.PESSIMISTIC_FORCE_INCREMENT
  • ,这是另一种很少使用的锁定模式。但是,这是您需要结合PESSIMISTICOPTIMISTIC机制的一种选择。在以下情况下,使用纯PESSIMISTIC_WRITE可能会失败:
  • 事务A使用乐观锁定并读取实体E
  • 事务B获得对实体E的WRITE锁
  • 事务B提交并释放E的锁
  • 事务A更新E并提交
  • 步骤4中的
  • ,如果版本B未被事务B递增,则没有什么阻止A覆盖B的更改。锁定模式LockModeType.PESSIMISTIC_FORCE_INCREMENT将强制事务B更新版本号,并导致事务A失败,使用OptimisticLockException,即使B使用悲观的锁定。
  • LockModeType.NONE
  • 如果实体不提供版本字段,则这是默认设置。这意味着没有启用锁定,将尽力解决冲突,并且不会检测到冲突。这是事务
  • 之外唯一允许的锁定模式

    08-17 23:31