LockModeType Jpa之间的区别

eat*_*ode 15 oracle concurrency hibernate jpa 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

Ond*_*Mih 30

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

乐观锁定完全由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.这里(ObjectDB)这里(OpenJPA)很好地解释 WRITE和READ锁之间的区别.
  4. javax.persistence.lock.timeout

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

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