我有一个带有版本字段的实体,可以使用乐观锁。但是必须确保所有更新均成功完成。所以我的计划是更新并保存该实体,捕获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;
}
这段代码与spring boot一起使用。 ISetEntity用于记住并仅更新特定字段。如果在此期间发生任何事情,则ISetEntityCondition是退出重试的方法。
我的问题是,首先,这是做事的最佳实践吗?
第二,以我的理解,在一个事务中查询并更新实体应该总是成功的,因为在整个事务期间其他线程无法到达该实体。但是我仍然可以通过乐观锁失败获得StaleObjectStateException,为什么会发生这种情况?