JPA本质上提供了两种锁定机制,以帮助同步对实体的访问。 两种机制都可以防止以下情况:两个事务在不知道的情况下相互覆盖数据。

通过实体锁定,我们通常希望通过2个并行事务来防止以下情况:

  1. 亚当的事务读取数据X
  2. 芭芭拉的交易读取数据X
  3. 亚当的交易会修改数据X,并将其更改为XA
  4. 亚当的事务将数据写入XA
  5. 芭芭拉的交易修改了数据X并将其更改为XB
  6. 芭芭拉的交易写数据XB

结果,亚当所做的更改完全被芭芭拉(Barbara)所取代,甚至没有引起她的注意。 像这样的场景有时被称为脏读 。 显然,理想的结果是Adam编写XA,而Barbara被迫在编写XB之前检查XA更改。

乐观锁的工作原理

乐观锁定基于这样的假设:冲突非常少见;如果发生冲突,则抛出错误是可以接受的,并且比防止冲突更方便。 允许其中一项交易正确完成,但其他任何交易都会例外回滚,并且必须重新执行或丢弃。

通过乐观锁定,亚当和芭芭拉可能出现以下情况:

  1. 亚当的事务读取数据X
  2. 芭芭拉的交易读取数据X
  3. 亚当的交易会修改数据X,并将其更改为XA
  4. 亚当的事务将数据写入XA
  5. 芭芭拉的交易修改了数据X并将其更改为XB
  6. Barbara的事务尝试写入数据XB,但接收到并出错
  7. 芭芭拉需要读取数据XA(或开始全新的交易)
  8. Barbara的事务修改了数据XA并将其更改为XAB
  9. Barbara的事务写入数据XAB

如您所见,芭芭拉被迫审查亚当的更改,如果她决定,她可能会修改亚当的更改并保存(合并更改)。 最终数据包含亚当和巴巴拉的变化。

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

悲观锁定如何工作

对于某些人来说,悲观锁定被认为是很自然的。 当事务需要修改实体(可以由另一个事务并行修改)时,事务将发出锁定该实体的命令。 所有锁将保留到事务结束,然后自动释放。

使用悲观锁,情况可能是这样的:

  1. 亚当的事务读取数据X
  2. 亚当的交易锁定X
  3. 芭芭拉的交易想要读取数据X,但是等待X已被锁定
  4. 亚当的交易会修改数据X,并将其更改为XA
  5. 亚当的事务将数据写入XA
  6. 芭芭拉的交易读取数据XA
  7. Barbara的事务修改了数据XA并将其更改为XAB
  8. Barbara的事务写入数据XAB

如我们所见,Barbara再次被迫编写XAB,其中也包含Adam所做的更改。 但是,该解决方案与乐观方案完全不同–芭芭拉需要等待亚当的交易完成后才能读取数据。 此外,我们需要在两个事务中手动发出锁定命令,以使该方案起作用。 (由于我们不确定亚当或芭芭拉首先要处理哪个事务,因此两个事务都需要在修改数据之前先锁定数据。)乐观锁定比悲观锁定需要更多的设置,每个实体都需要使用version列,但随后我们不需要记住在交易中发出锁。 JPA自动执行所有检查,我们只需要处理可能的异常。

悲观锁定使用基础数据库提供的锁定机制锁定表中的现有记录。 JPA需要知道如何触发这些锁定,并且某些数据库不完全支持。

甚至JPA规范都说,不需要提供PESSIMISTIC_READ(因为许多数据库仅支持WRITE锁):

这是允许的,以使用实施LockModeType.PESSIMISTIC_WRITE其中LockModeType.PESSIMISTIC_READ请求,而不是相反。

JPA中可用锁类型的列表

首先,我想说的是,如果实体中提供了@Version列,则JPA会默认为此类实体打开乐观锁定。 您不需要发出任何锁定命令。 但是,您可以随时使用以下一种锁类型发出锁:

  1. LockModeType.Optimistic

    • 这确实是默认设置。 如ObjectDB所述,通常将其忽略。 在我看来,它只是存在的,这样您就可以动态地计算锁定模式,即使锁定最终是最优的,也可以进一步传递它。 虽然用例不是很可能,但是提供一个甚至引用默认值的选项也是一种很好的API设计。
    • 示例:Java
      LockModeType lockMode = resolveLockMode();
      A a = em.find(A.class, 1, lockMode);
  2. LockModeType.OPTIMISTIC_FORCE_INCREMENT
    • 这是很少使用的选项。 但是,如果您想锁定另一个实体对这个实体的引用,这可能是合理的。 换句话说,即使您未修改某个实体,您也希望锁定该实体的工作,但是其他实体也可能相对于该实体而被修改。
    • 例:
      • 我们有实体书和书架。 可以将Book添加到书架中,但是book没有对其书架的引用。 锁定将书移动到书架上的操作是合理的,这样一本书不会最终出现在两个书架中。 要锁定此操作,仅锁定当前书架实体是不够的,因为书还不必在书架上。 锁定所有目标书架也没有意义,因为它们在不同交易中可能会有所不同。 唯一有意义的是锁定书本实体本身,即使在我们这种情况下它没有被更改(它不保留对其书架的引用)。
  3. LockModeType.PESSIMISTIC_READ
    • 此模式类似于LockModeType.PESSIMISTIC_WRITE ,但有一点不同:在通过某种事务在同一实体上施加写锁定之前,它不应阻止读取实体。 它还允许其他事务使用LockModeType.PESSIMISTIC_READ锁定。 WRITE和READ锁之间的区别在这里(ObjectDB)和这里(OpenJPA)都有很好的解释。 但是,由于规范允许,很多情况下,它的行为类似于LockModeType.PESSIMISTIC_WRITE ,许多提供程序并未单独实现它。
  4. LockModeType.PESSIMISTIC_WRITE
    • 这是LockModeType.PESSIMISTIC_READ的增强版本。 有了WRITE锁定后,JPA借助数据库将阻止任何其他事务读取该实体,而不仅仅是像READ锁定那样进行写入。
  5. LockModeType.PESSIMISTIC_FORCE_INCREMENT
    • 这是另一种很少使用的锁定模式。 但是,这是您需要结合PESSIMISTICOPTIMISTIC机制的一种选择。 在以下情况下,使用普通的PESSIMISTIC_WRITE可能会失败:

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

为了发出某种类型的锁,JPA提供了以下方法:

  • 一些EntityManager方法接受一个可选参数来指定锁定类型,例如:

    • find(类entityClass,Object primaryKey,LockModeType lockMode)
  • 查询还提供setLockMode(LockModeType lockMode)方法来锁定将由查询检索的所有实体

您可以在JPA中使用两种类型的锁定机制中的任何一种。 如果您使用类型PESSIMISTIC_FORCE_INCREMENT悲观锁,也可以在必要时将它们混合使用。

  • 要了解更多信息,请阅读Vlad Mihalcea的优秀博客。

翻译自: https://www.javacodegeeks.com/2016/02/differences-jpa-entity-locking-modes.html

JPA实体锁定模式的差异相关推荐

  1. jpa 关联实体的关联实体_JPA实体锁定模式的差异

    jpa 关联实体的关联实体 JPA本质上提供了两种锁定机制,以帮助同步对实体的访问. 两种机制都可以防止以下情况:两个事务在不知道的情况下相互覆盖数据. 通过实体锁定,我们通常希望通过2个并行事务来防 ...

  2. JPA实体中数据库生成ID的最终指南1

    只需用@ID注释JPA实体的ID字段,并允许DB关心其余的!在某些情况下,缺省值应该改变.在本文中,我们将看到更改ID生成策略会如何影响应用程序的性能. 根据JPA规范,Entity是满足以下要求的J ...

  3. MyEclipse开发教程:使用REST Web Services管理JPA实体(四)

    2019独角兽企业重金招聘Python工程师标准>>> MyEclipse 在线订购年终抄底促销!火爆开抢>> MyEclipse最新版下载 使用REST Web Ser ...

  4. hibernate工厂模式_Hibernate锁定模式–乐观锁定模式如何工作

    hibernate工厂模式 显式乐观锁定 在上一篇文章中 ,我介绍了Java持久性锁定的基本概念. 隐式锁定机制可防止丢失更新 ,它适用于我们可以主动修改的实体. 尽管隐式乐观锁定是一种广泛使用的技术 ...

  5. Hibernate锁定模式– OPTIMISTIC_FORCE_INCREMENT锁定模式如何工作

    介绍 在我以前的文章中 ,我解释了OPTIMISTIC锁定模式是如何工作的,以及它如何帮助我们同步外部实体状态更改. 在本文中,我们将介绍OPTIMISTIC_FORCE_INCREMENT锁定模式的 ...

  6. Hibernate锁定模式– PESSIMISTIC_FORCE_INCREMENT锁定模式如何工作

    介绍 在上 一篇 文章中 ,我介绍了OPTIMISTIC_FORCE_INCREMENT锁定模式,并将其应用于将子实体版本更改传播到锁定的父实体. 在本文中,我将介绍PESSIMISTIC_FORCE ...

  7. Hibernate锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作

    介绍 Java Persistence API带有完善的并发控制机制,支持隐式和显式锁定. 隐式锁定机制很简单,它依赖于: 乐观锁定:实体状态更改可以触发版本增加 行级锁定:基于当前运行的事务隔离级别 ...

  8. jpa 实体映射视图_JPA教程:实体映射-第2部分

    jpa 实体映射视图 在上一篇文章中,我展示了一种持久保存实体的简单方法. 我解释了JPA用于确定实体默认表的默认方法. 假设我们要覆盖此默认名称. 我们之所以喜欢这样做,是因为数据模型是以前设计和修 ...

  9. jpa 实体映射视图_JPA教程:实体映射-第3部分

    jpa 实体映射视图 在上一篇文章中,我展示了两种读取/写入持久实体状态的不同方法-字段和属性. 使用字段访问模式时,JPA使用反射直接从实体的字段读取状态值. 如果我们没有明确指定列名,它将直接将字 ...

最新文章

  1. Vivado 随笔(1) 综合属性之 ram_style rom_style?
  2. hbuilderx 2.9.8 公用css样式_浅谈关于vue中scss公用的解决方案
  3. Java Hashmap:如何从价值中获取关键?
  4. 正则表达式中^的用法
  5. python从入门到精通书-100G Python从入门到精通全套资料!
  6. 制作基于http的yum源2
  7. 【Android开发经验】android:windowSoftInputMode属性具体解释
  8. 硬核!尽量避免 BUG 手法
  9. IE盒模型和标准盒模型
  10. 程序员必知的8大排序(三)-------冒泡排序,快速排序(java实现) .
  11. 【T_SQL】 基础 事务
  12. configparser操作配置文件
  13. 什么是宇宙安全声明_《三体》三体人是否知道如何向宇宙发表安全声明?
  14. JavaScript总结(六)
  15. 【Python CheckiO 题解】Multicolored Lamp
  16. 基于 VS 2010 阐述C# 4个特性
  17. 支付宝搜索升级:品牌商可在品牌直达专区投放优惠券
  18. php读取pdf文件乱码,使用php读取pdf文件
  19. Android权限管理
  20. visual studio 容器工具首次加载太慢 vsdbg\vs2017u5 exists, deleting 的解决方案

热门文章

  1. 考研生的努力程度是有多恐怖!
  2. el表达式与jstl的用法
  3. 最全三大框架整合(使用映射)——数据库资源文件jdbc.properties
  4. 最全三大框架整合(使用映射)——DeptAction.java
  5. React向对象数组进行赋值
  6. 2016蓝桥杯省赛---java---B---1(有奖猜谜)
  7. 虚拟机安装centeros7 无法连接网络 virsh命令找不到 删除多余的vir0 不然dubbo会有问题
  8. android:background大小,小Demo小知识-android:foreground与android:background
  9. 利用树的先序和后序遍历打印os中的目录树
  10. vaadin_Vaadin提示:延迟加载和商品标识