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

РЕДАКТИРОВАТЬ: как указано в комментариях, лучший способ, кажется,

  1. получить постоянную сущность из контекста (A)
  2. создать новый, чистый (отдельный / временный) объект (B)
  3. скопировать все свойства (A) в (B)
  4. установить все свойства в (B) с тем, что исходит от DTO (может потребоваться преобразование)
  5. объединить (B) -> получить LockException, если @Version не соответствует

0 ответов

Другие вопросы по тегам