介绍

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

使用LockModeType.OPTIMISTIC ,将在当前正在运行的事务结束时检查锁定的实体版本,以确保我们不使用陈旧的实体状态。 由于应用程序级验证的性质 ,该策略易受竞争条件的影响,因此需要附加的悲观锁 。

LockModeType.OPTIMISTIC_FORCE_INCREMENT不仅会检查预期的锁定实体版本,还会对其进行递增。 检查和更新都发生在同一UPDATE语句中,因此利用了当前数据库事务隔离级别和关联的物理锁定保证。

值得注意的是,即使当前运行的事务未更改实体状态,锁定的实体版本也会被提高。

集中版本控制用例

作为练习,我们将模拟一个集中化的版本控制系统 ,其建模如下:

存储库是我们的系统根实体,每个状态更改都由Commit子实体表示。 每个Commit可能包含一个或多个Change组件,这些组件作为单个原子工作单元传播。

存储库版本随着每个新的Commit而增加。 为简单起见,我们只验证存储库实体版本,尽管更现实的方法肯定会检查每个单独的文件版本(以允许无冲突的提交并发进行)。

测试时间

首先,我们应该检查OPTIMISTIC_FORCE_INCREMENT锁定模式是否符合我们的用例要求:

doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {Repository repository = (Repository) session.get(Repository.class, 1L);session.buildLockRequest(new LockOptions(LockMode.OPTIMISTIC_FORCE_INCREMENT)).lock(repository);Commit commit = new Commit(repository);commit.getChanges().add(new Change("README.txt", "0a1,5..."));commit.getChanges().add(new Change("web.xml", "17c17..."));session.persist(commit);return null;}
});

此代码生成以下输出:

#Alice selects the Repository and locks it using an OPTIMISTIC_FORCE_INCREMENT Lock Mode
Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} #Alice makes two changes and inserts a new Commit
Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]}
Query:{[insert into commit (id, repository_id) values (default, ?)][1]}
Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][1,0a1,5...,README.txt]}
Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][1,17c17...,web.xml]} #The Repository version is bumped up
Query:{[update repository set version=? where id=? and version=?][1,1,0]}

我们的用户选择了一个存储库并发布了一个新的Commit 。 在交易结束时, 存储库版本也会增加(因此记录新的存储库状态更改)。

冲突检测

在下一个示例中,我们将有两个用户(爱丽丝和鲍勃)同时提交更改。 为了避免丢失更新 ,两个用户都获得了显式的OPTIMISTIC_FORCE_INCREMENT锁定模式。

在Alice获得提交机会之前,Bob刚刚完成了交易并增加了Repository版本。 Alice事务将回滚,并引发不可恢复的 StaleObjectStateException

为了模拟冲突检测机制,我们将使用以下测试方案:

doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {Repository repository = (Repository) session.get(Repository.class, 1L);session.buildLockRequest(new LockOptions(LockMode.OPTIMISTIC_FORCE_INCREMENT)).lock(repository);executeAndWait(new Callable<Void>() {@Overridepublic Void call() throws Exception {return doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session _session) {Repository _repository = (Repository) _session.get(Repository.class, 1L);_session.buildLockRequest(new LockOptions(LockMode.OPTIMISTIC_FORCE_INCREMENT)).lock(_repository);Commit _commit = new Commit(_repository);_commit.getChanges().add(new Change("index.html", "0a1,2..."));_session.persist(_commit);return null;}});}});Commit commit = new Commit(repository);commit.getChanges().add(new Change("README.txt", "0a1,5..."));commit.getChanges().add(new Change("web.xml", "17c17..."));session.persist(commit);return null;}
});

生成以下输出:

#Alice selects the Repository and locks it using an OPTIMISTIC_FORCE_INCREMENT Lock Mode
Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} #Bob selects the Repository and locks it using an OPTIMISTIC_FORCE_INCREMENT Lock Mode
Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} #Bob makes a change and inserts a new Commit
Query:{[insert into commit (id, repository_id) values (default, ?)][1]}
Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][1,0a1,2...,index.html]} #The Repository version is bumped up to version 1
Query:{[update repository set version=? where id=? and version=?][1,1,0]} #Alice makes two changes and inserts a new Commit
Query:{[insert into commit (id, repository_id) values (default, ?)][1]}
Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][2,0a1,5...,README.txt]}
Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][2,17c17...,web.xml]} #The Repository version is bumped up to version 1 and a conflict is raised
Query:{[update repository set version=? where id=? and version=?][1,1,0]}
INFO  [main]: c.v.h.m.l.c.LockModeOptimisticForceIncrementTest - Failure:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) :
[com.vladmihalcea.hibernate.masterclass.laboratory.concurrency.
LockModeOptimisticForceIncrementTest$Repository#1]

此示例表现出与典型的隐式乐观锁定机制相同的行为。 唯一的区别在于版本更改发起者。 尽管隐式锁定仅适用于修改实体,但显式锁定可以跨任何托管实体使用(不考虑实体状态更改要求)。

结论

因此, OPTIMISTIC_FORCE_INCREMENT对于将子实体状态更改传播到未修改的父实体非常有用。 通过简单地锁定它们的公共父代,此模式可以帮助我们同步各种实体类型。

当子实体状态更改必须触发父实体版本增加时,您可能要遵循显式的OPTIMISTIC_FORCE_INCREMENT锁定模式。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/02/hibernate-locking-patterns-optimistic_force_increment-lock-mode-work.html

Hibernate锁定模式– OPTIMISTIC_FORCE_INCREMENT锁定模式如何工作相关推荐

  1. 休眠锁定模式– OPTIMISTIC_FORCE_INCREMENT锁定模式如何工作

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

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

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

  3. 休眠锁定模式– PESSIMISTIC_FORCE_INCREMENT锁定模式如何工作

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

  4. 休眠锁定模式–乐观锁定模式如何工作

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

  5. mysql事务模式怎么查_Mysql InnoDB中的查询事务模式与锁定select ..for update

    在 InnoDB 的行锁中使用所谓的 next-key locking.这就意味着,除了索引记录外,InnoDB 还可以锁定该索引记录前部"间隙" ('gap') 以阻塞其它用户在 ...

  6. 对称加密、工作模式和填充模式

    对称加密密钥长度分析 DES秘钥长度:8个字符 AES秘钥长度:16个字符 DES加密后密文长度是8的整数倍 AES加密后密文长度是16的整数倍 工作模式和填充模式 IOS加密,android没有解密 ...

  7. rabbitmq几种工作模式_RabbitMQ六种队列模式-简单队列模式

    在官网的教程中,描述了如上六类工作队列模式: 简单队列模式:最简单的工作队列,其中一个消息生产者,一个消息消费者,一个队列.也称为点对点模式. 工作模式:一个消息生产者,一个交换器,一个消息队列,多个 ...

  8. apache 工作模式prefork进程模式和worker线程模式参式详解和推荐设置

    一apache工作模式: 1.prefork进程模式: prefork模式参数说明: prefork模式推荐设置: 二.apache worker模式: 1. 参数 三.prefork和worker模 ...

  9. Linux Vim三种工作模式(命令模式、输入模式和编辑模式)详解

    通过前面的学习我们知道,Linux 系统中所有的内容都以文件的形式进行存储,当在命令行下更改文件内容时,常会用到文本编辑器. 我们首选的文本编辑器是 Vim(至于为什么,可查看<Vi和Vim的区 ...

最新文章

  1. UNIX网络编程——客户/服务器程序设计示范(一)
  2. Linux awk+uniq+sort 统计文件中某字符串出现次数并排序
  3. SpringBoot源码笔记分析
  4. android获取屏幕的分辨率方法
  5. 微信小程序简介、发展史、小程序的优点、申请账号、开发工具、初识wxml文件和wxss文件
  6. (71)信号发生器DDS方波设计 (一)(第15天)
  7. Python+OpenGL切分图形窗口在多视区中显示不同动画
  8. 大数据之-Hadoop3.x_MapReduce_编程规范---大数据之hadoop3.x工作笔记0086
  9. hdu2074java
  10. C# abstract ,virtual ,override,new --比较好的文章
  11. 程序员记录biji的工具_程序员专用笔记 Quiver
  12. 程序、算法和数据结构的关系
  13. Python学习——语法错误与异常
  14. 数学建模养老保险问题matlab,全国大学生数学建模竞赛C题 企业退休职工养老金制度的改革...
  15. Kotlin入门:var和val的区别
  16. 【LeetCode】括号(有效括号、括号生成、最长有效括号)
  17. python 横坐标旋转_球坐标/python实现中的旋转问题
  18. pycharm申请学生账号收不到邮件问题(不是你收不到而是你没找到,邮件被拦截了)
  19. php emoji 保存 显示不出来,PHP导出带有emoji表情的文本到excel文件出问题了
  20. lottie.js动画插件自定义机器人行走

热门文章

  1. P2101-命运石之门的选择【dp,离散化】
  2. jzoj3512-游戏节目【树状数组,双向dfs】
  3. 2021 CCPC E. 被遗忘的计划(循环卷积+快速幂)
  4. 照看小猫(nowcoder 217602)
  5. MongoDB投影字段
  6. 汇编语言(二十四)之输出n行星号
  7. 汇编语言(十六)之三数值求和
  8. 漫画:什么是SnowFlake算法
  9. 史上最全Java多线程面试题
  10. 全球如何保证区块生成是匀速的?