一尘不染

Jpa LockModeType之间的区别

hibernate

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

  1. LockModeType.Optimistic

    • 它在提交时增加版本。
    • 这里的问题是:如果我的实体中有版本列,并且如果未指定此锁定模式,则它的工作方式也类似,那么它的用途是什么?
    • LockModeType.OPTIMISTIC_FORCE_INCREMENT

    • 即使未更新实体,它也会在此处增加版本列。

    • 但是,如果在提交此事务之前有任何其他进程在同一行中进行了更新,它的用途是什么?无论如何,该交易将失败。那么这个有什么用呢LockModeType
    • LockModeType.PESSIMISTIC_READ

    • 此锁定模式发出a 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

阅读 1693

收藏
2020-06-20

共1个答案

一尘不染

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

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

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

现在到锁类型列表:

  1. LockModeType.Optimistic

    • 如果实体指定版本字段,则这是默认值。对于没有版本列的实体,不能保证在任何JPA实现中都不能使用这种类型的锁。如ObjectDB所述,通常会忽略此模式。在我看来,它只是存在的,这样您就可以动态地计算锁定模式,即使锁定最终是最优的,也可以进一步传递它。虽然用例不是很可能,但是提供一个甚至引用默认值的选项也是一种很好的API设计。
    • 例:

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

  1. LockModeType.OPTIMISTIC_FORCE_INCREMENT

    • This is a rarely used option. But it could be reasonable, if you want to lock referencing this entity by another entity. In other words you want to lock working with an entity even if it is not modified, but other entities may be modified in relation to this entity.
    • 示例:我们有实体书和书架。可以将Book添加到书架中,但是book没有对其书架的引用。锁定将书移动到书架上的操作是合理的,这样一本书在此交易结束之前不会落在另一个书架中(由于另一笔交易)。要锁定此操作,仅锁定当前书架实体是不够的,因为书还不必在书架上。锁定所有目标书架也没有意义,因为它们在不同交易中可能会有所不同。唯一有意义的是锁定书本实体本身,即使在我们这种情况下它没有被更改(它不保留对其书架的引用)。
    • LockModeType.PESSIMISTIC_READ

    • 此模式与相似LockModeType.PESSIMISTIC_WRITE,但有一点不同:在通过某种事务在同一实体上施加写锁定之前,它不应阻止读取实体。它还允许使用锁定其他事务LockModeType.PESSIMISTIC_READ。WRITE和READ锁之间的区别在这里(ObjectDB)这里(OpenJPA)都有很好的解释。如果一个实体已经被另一个事务锁定,则对其进行任何锁定尝试都将引发异常。可以将此行为修改为在引发异常并回滚事务之前等待一段时间以释放锁。为此,javax.persistence.lock.timeout请在引发异常之前指定提示以毫秒为单位。有多种方法可以在多个级别上执行此操作,如Java EE教程

    • LockModeType.PESSIMISTIC_WRITE

    • 这是的更强版本LockModeType.PESSIMISTIC_READ。当WRITE锁定到位时,JPA在数据库的帮助下将阻止任何其他事务读取实体,而不仅仅是像READ锁定时一样进行写入。

    • 没有规定如何在JPA提供程序中与基础DB合作实现此方法。对于Oracle,我想说Oracle不能提供接近READ锁的功能。SELECT...FOR UPDATE确实是一个WRITE锁。这可能是hibernate中的错误,或者是一个决定,而不是实现自定义的“较软” READ锁,WRITE而是使用了“较硬” 锁。这在大多数情况下不会破坏一致性,但是不会保留所有READ带锁的规则。您可以使用READ锁和长时间运行的事务运行一些简单的测试,以了解是否有更多事务能够READ在同一实体上获取锁。这应该是可能的,但不能使用WRITE锁。
    • LockModeType.PESSIMISTIC_FORCE_INCREMENT

    • 这是另一种很少使用的锁定模式。但是,这是您需要结合使用PESSIMISTICOPTIMISTIC机制的一种选择。PESSIMISTIC_WRITE在以下情况下,使用Plain 将失败:

    • 事务A使用乐观锁定并读取实体E
    • 事务B获得对实体E的WRITE锁定
    • 事务B提交并释放E的锁
    • 事务A更新E并提交
    • 在第4步中,如果版本B未被事务B增加,则没有什么阻止A覆盖B的更改。锁定模式LockModeType.PESSIMISTIC_FORCE_INCREMENT将强制事务B更新版本号,并导致事务A失败OptimisticLockException,即使B使用悲观锁定。
    • LockModeType.NONE

    • 如果实体不提供版本字段,则为默认设置。这意味着没有启用锁定,将尽力解决冲突,并且不会检测到冲突。这是事务外部唯一允许的锁定模式

2020-06-20