来自JPA规范 http://download.oracle.com/otndocs/jcp/persistence-2_1-fr-eval-spec/index.html, 部分3.4.2:
实体可以访问其版本字段或属性的状态,或者
导出一个方法供应用程序用来访问版本,但是
不得修改版本值。除章节中注明的例外情况外
4.10 中,仅允许持久化提供者设置或更新对象中版本属性的值。
version 属性的目的是防止我们在当前持久化上下文中加载对象后可能发生的并发更新,Hibernate 通过忽略您手动设置的任何值来实现它,而是使用从数据库获取的值对象已加载。为了验证这一点,enable https://stackoverflow.com/a/2536835/4754790还打印绑定变量值,您会注意到使用了数据库中的值。
例如,在使用 DTO 时实际使用的标准解决方案是在从 DTO 更新实体状态时手动执行检查:
if (entity.getVersion() != dto.getVersion()) {
throw new OptimisticLockException("...");
}
当然,您可以通过从为所有可版本实体提供此检查的基类进行扩展,或在某些 util 方法中进行扩展,使其更加通用。例如,有些作者直接在版本设置器中执行此操作:
public void setVersion(long version) {
if (this.version != version) {
throw new OptimisticLockException("...");
}
}
Hibernate 自动对分离实体执行此检查,如在实现中所示DefaultMergeEventListener https://github.com/hibernate/hibernate-orm/blob/5.1/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java#L316:
else if (isVersionChanged(entity, source, persister, target)) {
if (source.getFactory().getStatistics().isStatisticsEnabled()) {
source.getFactory().getStatisticsImplementor()
.optimisticFailure(entityName);
}
throw new StaleObjectStateException(entityName, id);
}