JPA Блокировка в веб-приложении
Я пытаюсь реализовать блокировку в приложении JPA/Hibernate, чтобы определить, когда клиент пытается выдвинуть изменения в устаревшей версии объекта.
Я решил выставить dto (представляющий подмножество домена) через службы REST. В настоящее время я могу легко обнаруживать обновления параллельных транзакций, но не могу заставить его обнаруживать обновления "старых" сущностей. Я объясню:
- # 1 2 параллельные транзакции, управляющие одной и той же сущностью, каждая из которых прикреплена к своему диспетчеру сущностей, правильно защищены от грязных чтений (последним коммитом становится исключение OptimisticLockingException)
# 2 2 одновременных пользователя, манипулирующих одним и тем же объектом с помощью своего внешнего интерфейса и совершающих две разные, не параллельные транзакции, НЕ получают никаких исключений блокировки. Это потому, что, используя DTO, часть кода для обновления выглядит примерно так:
- начать транзакцию
- получить постоянную сущность для обновления от менеджера
- скопировать то, что имеет значение от dto к этому объекту
- совершить
... но ничто (JPA, Hibernate или что-то еще) никогда не проверяет соответствие между версией dto и версией сущности... (ps: попытка установить поле @Version с версией, указанной в dto, как указано JPA, привести к странным результатам)
Основываясь на том, что я видел, и отладке и чтении документации, я закончил тем, что написал такой код:
abstract class AbstractBusinessService {
private static final Logger LOG = LoggerFactory.getLogger(AbstractBusinessService.class);
protected final void checkEntityVersion(Long givenVersion, VersionedEntity<?> entity) {
if (givenVersion == null) {
LOG.warn("no version have been provided. unable to check for concurrent modification");
} else if (entity == null) {
LOG.warn("the given entity is null");
} else if (entity.getVersion() != givenVersion.longValue()) {
throw new LockingException("The persistent entity " + entity.getClass().getName() + "#" + entity.getId()
+ " has a newer version than expected (" + givenVersion + " vs. " + entity.getVersion() + ")");
}
}
}
... вызывается перед каждой операцией "обновления"... Это, очевидно, работает как шарм, но добавляет некоторую сложность на бизнес-уровне, для темы, которая связана исключительно с постоянством и не должна быть видна на бизнес-уровне...
Прав ли я в том смысле, что это вещь "сделай сам", и нет ничего доступного для реализации # 2? Я что-то пропустил?? Как вы решаете эту проблему в своем развитии?
Большое спасибо за чтение,
SP
РЕДАКТИРОВАТЬ: как указано в комментариях, лучший способ, кажется,
- получить постоянную сущность из контекста (A)
- создать новый, чистый (отдельный / временный) объект (B)
- скопировать все свойства (A) в (B)
- установить все свойства в (B) с тем, что исходит от DTO (может потребоваться преобразование)
- объединить (B) -> получить LockException, если @Version не соответствует