JPA: OptimisticLockException and Cascading

前端 未结 2 2173
刺人心
刺人心 2021-02-10 23:03

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.

I\'m uncertain how I should

2条回答
  •  萌比男神i
    2021-02-10 23:38

    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();
        }
    }
    

    and the according Service method

    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;
        }
    }
    

    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.

提交回复
热议问题