Spring Data JPA:删除乐观锁定语义 [英] Spring Data JPA: Delete Optimistic Locking semantics

查看:123
本文介绍了Spring Data JPA:删除乐观锁定语义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个带有@Version列的实体Foo.如果要删除它,我希望Spring Data JPA和/或Hibernate检查@Version列的当前值是否与数据库中的值匹配.如果不是这样,则应拒绝删除.对于分离的实体,这可以按预期工作:

There's an entity Foo with a @Version column. If I want to delete it I expect Spring Data JPA and/or Hibernate to check whether the current value of the @Version column matches the one in the database. If it does not, the deletion should be rejected. This works as expected with a detached entity:

@Transactional
public void delete(Foo foo) {
    fooRepository.delete(foo); // throws ObjectOptimisticLockingFailureException
}

但是,如果我先从存储库中加载实体,然后使用不同版本在同一事务中将其删除,则无论@Version列的值如何,删除都会通过:

But if I load the entity first from the repository and then delete it within the same transaction using a different version the deletion passes regardless of the value of @Version column:

@Transactional
public void delete(int fooId, long version) {
    Foo foo = fooRepository.findOne(fooId);
    foo.setVersion(version);
    fooRepository.delete(foo); // passes regardless of value of version
}

当我查看Hibernate调试输出时,将执行版本比较(delete from foo where id=? and version=?),但效果不理想.

When I look into the Hibernate debug output, the version comparison is performed (delete from foo where id=? and version=?) but not with the effect I'm expecting.

我想念什么?

推荐答案

来自

实体可以访问其版本字段或属性的状态,或者 导出供应用程序访问版本的方法,但是 不得修改版本值.除了本节中提到的例外 4.10,仅允许持久性提供程序设置或更新对象中version属性的值.

An entity may access the state of its version field or property or export a method for use by the application to access the version, but must not modify the version value. With the exception noted in section 4.10, only the persistence provider is permitted to set or update the value of the version attribute in the object.

version属性的目的是防止我们在当前持久性上下文中加载对象后可能发生的并发更新,并且Hibernate通过忽略您手动设置的任何值来实现它,而是使用从加载对象时的数据库.为了验证这一点,还启用打印绑定变量值,您会注意到使用了数据库中的值.

The purpose of the version property is to guard us from concurrent updates that may happen after the object is loaded in the current persistence context, and Hibernate implements it by ignoring any value you set manually, but rather uses the value obtained from the database when the object is loaded. To verify this, enable printing of bound variable values as well and you will notice that the value from the database is used.

例如,在实际使用DTO时使用的标准解决方案是在从DTO更新实体状态时手动执行检查:

For example, the standard solution that is used in practice when working with DTOs is to perform the check manually when updating entity state from DTOs:

if (entity.getVersion() != dto.getVersion()) {
    throw new OptimisticLockException("...");
}

当然,您可以通过从为所有可版本控制的实体提供此检查的基类或某些util方法中扩展出通用性.例如,有些作者直接在版本设置器中执行此操作:

Of course you can make this more generic by extending from a base class that provides this check for all version-able entities, or in some util method. For example, some authors do it in the version setter directly:

public void setVersion(long version) {
    if (this.version != version) {
      throw new OptimisticLockException("...");
    }
} 

Hibernate对分离的实体自动执行此检查,如

Hibernate performs this check automatically for detached entities, as can be seen in the implementation of DefaultMergeEventListener:

else if (isVersionChanged(entity, source, persister, target)) {
    if (source.getFactory().getStatistics().isStatisticsEnabled()) {
        source.getFactory().getStatisticsImplementor()
            .optimisticFailure(entityName);
    }
    throw new StaleObjectStateException(entityName, id);
}

这篇关于Spring Data JPA:删除乐观锁定语义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆