Подтвердить что ты не робот

Как перезапустить транзакции в тупике/блокировке-тайм-ауте в Spring?

Какова наилучшая практика реализации перезагрузки транзакций при исключениях блокировки или блокировки таймаута при использовании Spring (в частности, рекомендуемый подход Spring: декларативные транзакции)?

Спасибо,

Асаф

4b9b3361

Ответ 1

Мне кажется, что сам Spring должен иметь хороший ответ на этот вопрос (в виде документации, по крайней мере, или какого-то перехватчика повторных попыток). Увы, это не так.

Вероятно, лучший способ обработки повторных попыток (если вы хотите продолжать "декларативный" о вещах) заключается в том, чтобы написать собственную реализацию перехватчика, которая будет автоматически повторять транзакцию сконфигурированное количество раз. Для начала изучите Spring TransactionInterceptor, который управляет началом/откатом/фиксацией поведения для декларативных транзакций. Если вы используете Hibernate, обратите внимание на то, как он обрабатывает привязку/отключение привязки Hibernate к текущему потоку.

Остерегайтесь, если вы используете Hibernate:

  • Ваш "перехватчик повторных попыток" должен обязательно отменить предыдущий сеанс Hibernate, связанный с потоком, и переподтвердить новый. Когда исключение (например, тупик) выбрасывается из кода Hibernate/JDBC, соответствующий сеанс Hibernate отравляется и его нужно отбрасывать. (session.clear() недостаточно).
  • Будьте осторожны, если ваши методы транзакционных служб используют объекты сеанса Hibernate в качестве параметров метода. Повторите попытку, когда вы reset сеанс Hibernate, эти объекты будут отсоединены. Вам понадобится повторно привязать их, если метод службы предполагает, что они подключены (например, если они используют ленивые загруженные свойства, которые получают доступ к методу службы, или если вы пытаетесь их сохранить и т.д.). В целом, лучше, если вы не используйте объекты Hibernate в качестве параметров для методов транзакционных служб.
  • Вы будете внедрять MethodInterceptor.invoke() - экземпляр MethodInvocation, который будет передан в это, может быть с сохранением состояния; вам может понадобиться клонировать его перед использованием в перехватчике.

Ответ 2

Я рекомендую использовать класс org.springframework.retry.interceptor.RetryOperationsInterceptor из проекта spring retry , настроенного как это:

<aop:config>
    <aop:pointcut id="transactional" expression="execution(* com...*Service.remoteCall(..))" />
    <aop:advisor pointcut-ref="transactional" advice-ref="retryAdvice" order="-1"/>
</aop:config>

<bean id="retryAdvice" class="org.springframework.retry.interceptor.RetryOperationsInterceptor"/>

Но если вы все еще хотите реализовать его самостоятельно, хороший пример AOP из spring документации.

Ответ 3

Нет универсального ответа, поскольку он зависит от специфики приложения. Например, вы можете выполнить автоматический перезапуск транзакции или уведомить пользователя об ошибке работы и запросить явное подтверждение повтора и т.д.

Я бы использовал AOP в случае автоматического перезапуска.

Ответ 4

У меня был тот же вопрос несколько лет назад, и я написал мое собственное решение как аспект AOP, который заканчивается таким, как это в вашем код:

  @RetryTransaction
  @Transactional
  public void doSomething() {
      ....
  }