LockModeType Jpa 之间的区别

Difference between LockModeType Jpa

我对 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 为什么需要版本增量?

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

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

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

现在进入锁类型列表:

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

       `LockModeType lockMode = resolveLockMode();
     A a = em.find(A.class, 1, lockMode);`
    
  1. LockModeType.OPTIMISTIC_FORCE_INCREMENT
  • 这是一个很少使用的选项。但它可能是合理的,如果你想锁定另一个实体引用这个实体。换句话说,您想要锁定使用一个实体,即使它没有被修改,但其他实体可能会相对于这个实体被修改。
  • 示例:我们有实体 Book and Shelf。可以将书添加到书架,但书没有任何对其书架的引用。锁定将一本书移动到一个书架的动作是合理的,这样一本书就不会在该事务结束之前最终进入另一个书架(由于另一个事务)。要锁定此操作,仅锁定当前书架实体是不够的,因为这本书还没有上架。锁定所有目标书架也没有意义,因为它们在不同的交易中可能会有所不同。唯一有意义的是锁定书籍实体本身,即使在我们的例子中它没有被改变(它不持有对其书架的引用)。
  1. LockModeType.PESSIMISTIC_READ
  • 此模式类似于LockModeType.PESSIMISTIC_WRITE,但有一点不同:在某个事务对同一实体设置写锁之前,它不应阻止读取该实体。它还允许其他事务使用 LockModeType.PESSIMISTIC_READ 锁定。 WRITE 和 READ 锁的区别很好解释here (ObjectDB) and here (OpenJPA). If an entity is already locked by another transaction, any attempt to lock it will throw an exception. This behavior can be modified to waiting for some time for the lock to be released before throwing an exception and roll back the transaction. In order to do that, specify the javax.persistence.lock.timeout hint with the number of milliseconds to wait before throwing the exception. There are multiple ways to do this on multiple levels, as described in the Java EE tutorial
  1. LockModeType.PESSIMISTIC_WRITE
  • 这是 LockModeType.PESSIMISTIC_READ 的更强版本。当 WRITE 锁到位时,JPA 在数据库的帮助下将阻止任何其他事务读取实体,而不仅仅是像使用 READ 锁那样写入。
  • 没有规定如何在 JPA 提供程序中与底层 DB 合作实现它。在您使用 Oracle 的情况下,我会说 Oracle 不提供接近 READ 锁的东西。 SELECT...FOR UPDATE 实际上是一个 WRITE 锁。这可能是休眠中的一个错误,或者只是一个决定,而不是实现自定义“更软”READ 锁,而是使用“更硬”WRITE 锁。这主要不会破坏一致性,但不会持有 READ 锁的所有规则。您可以 运行 使用 READ 锁和长 运行ning 事务进行一些简单测试,以查明是否有更多事务能够获取同一实体上的 READ 锁。这应该是可能的,而不是 WRITE 锁。
  1. 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 失败并显示OptimisticLockException,即使 B 正在使用悲观锁定。
  1. LockModeType.NONE
  • 如果实体不提供版本字段,则这是默认设置。这意味着没有启用锁定,冲突将在尽力而为的基础上解决,并且不会被检测到。这是事务之外唯一允许的锁定模式