У меня есть объект с полем версии, чтобы использовать оптимистическую блокировку.Но необходимо убедиться, что все обновления происходят успешно.Поэтому я планирую обновить и сохранить объект, перехватить исключительную ситуацию 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 для блокировки оптимиста, почему это происходит?