Оптимистическая блокировка с отношениями @ManyToOne JPA, когда родительский элемент не имеет @VersionJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Оптимистическая блокировка с отношениями @ManyToOne JPA, когда родительский элемент не имеет @Version

Сообщение Anonymous »

Я работаю над приложением, состоящим из объекта с высокой пропускной способностью, в котором мне нужно смягчить условия гонки, и некоторых редко изменяемых объектов домена.
Чтобы добиться этого, мы добавили Оптимистическая блокировка JPA к существующему приложению.
Пример:

Код: Выделить всё

@Entity
public class Payment {
@Id
protected Long id;
@Version
protected Long version;

protected String lastStatus; //the one I want to protect from concurrent processes
@ManyToOne
protected Channel inputChannel;

//Other columns
}

@Entity
public class Channel {
@Id
protected Long id;
// Not changing frequently (ever...), no version attribute here
}

Сценарий использования оптимистической блокировки прост: когда ответ удаленной системы и асинхронный тайм-аут происходят одновременно на нескольких узлах/потоках, выигрывает только одна транзакция, без обременения пессимистическими блокировками. Шаблон проектирования приложения: Контроллер(Запрос)-Менеджер(DTO)-Репозиторий(Entity).
Однако у меня есть метод обновления общего назначения, который может обновлять практически каждое поле в сущности. , в частности отношение к Каналу. Из-за функциональных ограничений не предполагается, что возникнут проблемы с условиями гонки.

Код: Выделить всё

@Transactional
public class PaymentManager {

public void update(PaymentDto dto){
var payment = repository.findById(dto.getId()).orElseThrow();
// perform all updates
// this INCLUDES changing the channel

if (dto.getInputChannel() != null && dto.getInputChannel().getId() != null) {
payment.setInputChannel(channelRepository.getReferenceById(dto.getInputChannel().getId()));
}

repository.save(payment);
}

@Retryable
public boolean upgradeStatus(Long paymentId, Status expectedStatus, Status newStatus) {
var payment = repository.findById(dto.getId()).orElseThrow();
if (!expectedStatus.name().equals(payment.getStatus()) {
return false;
}
payment.setStatus(newStatus.name());
repository.save(payment);
return true;
}
}

public class PaymentRepository extends JpaRepository.... {

@Lock(LockMode.OPTIMISTIC)
Optional findById(Long id);
}

Итак, чтобы упростить мне задачу (или признать, что я ленив), я сделал весь findById объектом оптимистической блокировки.
Но теперь проблема в том, что, судя по всему, Hibernate пытается выполнить проверку оптимистической блокировки и для объекта Channel

Код: Выделить всё

org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor@6e9bf992]
at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:191)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:117)
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:93)
[omitted]
org.springframework.messaging.MessageHandlingException: error occurred during processing message in 'MethodInvokingMessageProcessor' [org.springframework.integration.handler.MethodInvokingMessageProcessor@6e9bf992]
at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:191)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:117)
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:93)
[omitted]
...  401 common frames omitted
Caused by: org.hibernate.HibernateException: Unable to perform beforeTransactionCompletion callback: Cannot invoke "Object.equals(Object)" because the return value of "org.hibernate.engine.spi.EntityEntry.getVersion()" is null
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:1022)
at org.hibernate.engine.spi.ActionQueue.beforeTransactionCompletion(ActionQueue.java:546)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1982)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:169)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:267)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)
... 429 common frames omitted
Caused by: java.lang.NullPointerException: Cannot invoke "Object.equals(Object)" because the return value of "org.hibernate.engine.spi.EntityEntry.getVersion()" is null
at org.hibernate.action.internal.EntityVerifyVersionProcess.doBeforeTransactionCompletion(EntityVerifyVersionProcess.java:41)
at org.hibernate.engine.spi.ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion(ActionQueue.java:1016)
... 436 common frames omitted
При отладке кода Hibernate кажется, что EntityVerifyVersionProcess добавляется в список действий перед фиксацией как для платежа, так и для канала во время вызова findById, вероятно, потому, что аннотации к методу.
Похоже, Hibernate не догадывается (должен ли?), что меня не интересует отслеживание версии Channel, потому что я я не вношу никаких изменений в свое приложение. Канал — это практически неизменяемая сущность. Главным образом потому, что он может измениться, но метод обновления никогда не меняет содержимое канала.
Итак, мои вопросы:
  • Это нормальное поведение в JPA? Вам также нужно добавить блокировку ко всем зависимым объектам в отношениях дочерний->родительский?
  • Существует ли стандартный способ сообщить модели JPA, что ссылка на канал не подлежит для блокировки при загрузке объекта «Платеж»?
  • Или это может быть ошибка в Hibernate, который не обнаруживает, что канал не блокируется, и все еще пытается выполнить проверку?
[ОБНОВЛЕНИЕ]
После экспериментов выяснилось, что это НЕ связано с обновлением канала. Само присутствие объекта Channel в Платеже вызывает проблему

Подробнее здесь: https://stackoverflow.com/questions/793 ... no-version
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Оптимистическая блокировка с отношениями @ManyToOne JPA, когда родительский элемент не имеет @Version
    Anonymous » » в форуме JAVA
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Почему wp_get_theme()->get('Version') работает как аргумент wp_enqueue_styles, но не $version = wp_get_theme()->get('Ver
    Anonymous » » в форуме Php
    0 Ответы
    33 Просмотры
    Последнее сообщение Anonymous
  • Python3 Venv Version и System Version?
    Anonymous » » в форуме Python
    0 Ответы
    27 Просмотры
    Последнее сообщение Anonymous
  • Python3 Venv Version и System Version?
    Anonymous » » в форуме Python
    0 Ответы
    26 Просмотры
    Последнее сообщение Anonymous
  • Оптимистическая синхронизация для двоичного дерева поиска
    Anonymous » » в форуме JAVA
    0 Ответы
    3 Просмотры
    Последнее сообщение Anonymous

Вернуться в «JAVA»