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

介绍

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

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

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

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

集中版本控制用例

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

存储库提交更改乐观力增量

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

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

测试时间

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

doInTransaction(new TransactionCallable<Void>() {
	@Override
	public 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

显式锁定乐观力增量1

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

doInTransaction(new TransactionCallable<Void>() {
	@Override
	public 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>() {
			@Override
			public Void call() throws Exception {
				return doInTransaction(new TransactionCallable<Void>() {
					@Override
					public 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锁定模式。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值