Повторите попытку сбоя оптимистической блокировки и используйте пессимистическую блокировку, чтобы убедиться, что обновление происходит? - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть объект с полем версии, чтобы использовать оптимистическую блокировку.Но необходимо убедиться, что все обновления происходят успешно.Поэтому я планирую обновить и сохранить объект, перехватить исключительную ситуацию OptimisticLockingFailureException, если не удалось выполнить оптимистическую блокировку, повторно запросить последний объект, затем обновить определенное поле и снова попытаться сохранить объект.Повторите через несколько раз, если сбой по-прежнему вызывает оптимистическую блокировку, используйте пессимистическую блокировку (транзакция), чтобы убедиться, что обновление происходит.Вот мой код:

public Entity safeSave(Entity entity, Repository repository,
                       ISetEntity<Entity> setEntity, ISetEntityCondition<Entity> condition, long interval){
    if(!condition.meetCondition(entity)){
        return entity;
    }
    entity = setEntity.setEntity(entity);
    try {
        // If no optimistic exception, just save it normally.
        entity = (Entity) repository.save(entity);
    }catch (OptimisticLockingFailureException | OptimisticLockException e){
        // Optimistic lock exception occurs, and already tried some times,
        // use transaction and pessimistic lock to save.
        if(interval > maxWaitTime){
            Serializable entityId = entity.getId();
            final Class entityClass = entity.getClass();
            transactionService.executeTransaction(() -> {
                Entity newEntity = findOneForUpdate(entityId, entityClass, repository);
                newEntity = setEntity.setEntity(newEntity);                    
            });
            return (Entity) repository.findById(entityId).get();
        }
        // Optimistic lock exception occurs, sleep a little and try again.
        try{
            Thread.sleep(interval);
            entity = (Entity) repository.findById(entity.getId()).get();
            return safeSave(entity, repository, setEntity, condition, interval * 2);
        }catch (InterruptedException e1){
            Thread.currentThread().interrupt();
            e1.printStackTrace();
        }
    }
    catch (Exception e){
        e.printStackTrace();
    }
    return entity;
}

Этот фрагмент кода используется с пружинной загрузкой.ISetEntity предназначен для запоминания и обновления только определенных полей.ISetEntityCondition - это способ выйти из повтора, если что-то случится в течение периода.

Мой вопрос, во-первых, является ли это наилучшей практикой для действий?

Во-вторых, насколько я понимаю, запрос изатем обновление объекта в одной транзакции всегда должно быть успешным, потому что другой поток не может достичь объекта в течение всей транзакции.Но я все еще могу получить StaleObjectStateException для блокировки оптимиста, почему это происходит?

...