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

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

Спасибо

Асаф

Ответы [ 4 ]

15 голосов
/ 04 мая 2010

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

Вероятно, лучший способ обработки повторных попыток (если вы хотите продолжать «декларативно» относиться к вещам) - это написать собственную реализацию перехватчика, которая будет автоматически повторять транзакцию настроенное число раз. Для начала изучите Spring * TransactionInterceptor, который управляет поведением start / rollback / commit для декларативных транзакций. Если вы используете Hibernate, обратите внимание, как он обрабатывает привязку / отмену привязки сеанса Hibernate к текущему потоку.

На что обращать внимание при использовании Hibernate:

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

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

<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"/>

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

4 голосов
/ 24 марта 2015

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

  @RetryTransaction
  @Transactional
  public void doSomething() {
      ....
  }
4 голосов
/ 20 ноября 2009

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

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

...