JPA:OptimisticLockException和级联 [英] JPA: OptimisticLockException and Cascading

查看:134
本文介绍了JPA:OptimisticLockException和级联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我当前的项目中,我将Spring Data JPA与Hibernate一起使用,但是将其视为更笼统的问题,也应涵盖普通" JPA.

In my current project I use Spring Data JPA with Hibernate but consider this as a more general question that should also cover "plain" JPA.

我不确定使用@Version时应该如何处理OptimisticLockException.

I'm uncertain how I should deal with OptimisticLockException when using @Version.

由于我的应用程序的工作方式,某些关系具有CascadeType.PERSISTCascadeType.REFRESH,另一些关系也具有CascadeType.MERGE.

Due to how my application works some relationships have CascadeType.PERSIST and CascadeType.REFRESH, others also have CascadeType.MERGE.

  1. 在哪里处理OptimisticLockException

据我所知,

在服务层上处理此问题尤其不适用于CascadeType.MERGE,因为这样,有问题的实体可能是需要由另一服务处理的实体(我对每个实体类都有一个服务).

As far as I can tell handling this on the service layer won't work especially with CascadeType.MERGE because then the offending entity could be one that needs to be handled by another service ( I have a service per entity class).

问题是我正在创建一个框架,因此服务之上没有层,因此我可以将其委派"给我的框架用户,但看起来虚弱而懒惰".

Problem is I'm creating a framework and hence there is no layer above service so I could just "delegate" this to the user of my framework but that seems "weak and lazy".

  1. 确定已更改的违规实体和字段

如果发生OptimisticLockException,如何获取导致该问题的实体以及更改了哪些字段?

if a OptimisticLockException occurs, how do I get which entity caused the issue and what fields were changed?

是的,我可以调用getEntity(),但是如何将其转换为正确的Type,尤其是如果使用CascadeType.MERGE?该实体可能具有多种类型,因此想到了带有instanceof的if/switch,但这看起来像地狱一样难看.

Yes, i can call getEntity() but how do I cast that to the correct Type especially if CascadeType.MERGE was used? The entity could be of multiple types, so a if/switch with instanceof comes to mind but this seems ugly like hell.

一旦我使用了正确的类型,就需要获取版本之间的所有差异,但不包括某些字段,例如版本本身或lastModifiedDate.

Once I have the correct type I would need to get all the differences between the versions excluding certain fields like version itself or lastModifiedDate.

在我的脑海中还有HTTP 409,它指出在发生冲突的情况下响应应包含冲突字段.

In the back of my mind is also HTTP 409 which stated that in case of conflict response should contain the conflicting fields.

这是否有最佳实践模式"?

Is there a "best-practice-pattern" for all this?

推荐答案

困扰我的是,JPA(Hibernate)和Spring提供的异常实际上并未返回失败对象的当前版本.因此,如果用户需要决定要做什么,那么他显然需要查看更新的最新版本.只是智障他的电话似乎对我智障.我的意思是,您已经在事务中处于数据库级别,因此直接获取新的当前值没有花费...

What was bothering me is that the exceptions provided by JPA (Hibernate) and Spring do not actually return the current version of the failed object. So if a User needs to decide what to do, he obviously needs to see the updated, most current version. Just retarded an error to his call seems retarded to me. I mean you are already at database level in a transaction so getting the new current value directly has no cost...

我创建了一个新异常,其中包含对未能更新的实体的最新版本的引用:

I created a new Exception that holds a reference to the newest version of the entity that failed to update:

public class EntityVersionConflictException {

    @Getter
    private final Object currentVersion;

    public EntityVersionConflictException(
            ObjectOptimisticLockingFailureException lockEx,
            Object currentVersion){
        super(lockEx);
        this.currentVersion = currentVersion;
    }

    public Object getConflictingVersion() {
        return ((OptimisticLockException)getCause().getCause()).getEntity();
    }

    public Class getEntityClass() {
        return getCause().getPersistentClass();
    }

    @Override
    public ObjectOptimisticLockingFailureException getCause(){
        return (ObjectOptimisticLockingFailureException)super.getCause();
    }
}

以及相应的服务方法

try {
    return getRepository().save(entity);
} catch (ObjectOptimisticLockingFailureException lockEx) {
    // should only happen when updating existing entity (eg. merging)
    // and because entites do not use CascadeType.MERGE
    // the entity causing the issue will always be the of class
    // entity.getClass()
    // NOTE: for some reason lockEx.getPersistentClass() returns null!!!
    // hence comparing by class name...
    if (lockEx.getPersistentClassName().equals(entityClass.getName())) {
        T currentVersion = getById(entity.getId());
        throw new EntityVersionConflictException(lockEx, currentVersion);
    } else {
        throw lockEx;
    }
}

请注意评论.如果是CascadeType.MERGE,它将无法像这样工作,逻辑将必须复杂得多.每个实体类型都有1个服务,因此该服务必须保留对所有其他服务的引用,依此类推.

Note the comments. In case of CascadeType.MERGE this will not work like this, the logic would have to be much more complex. I have 1 service per entity type so that service would have to hold reference to all other services and so forth.

这篇关于JPA:OptimisticLockException和级联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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