Spring синхронизирует транзакции Hibernate и JMS

Я работаю над автономным приложением, которое использует JMS и Hibernate.

Документация предлагает использовать JTA, если я хочу, чтобы транзакции проходили через оба ресурса.

Однако сейчас, с аннотированным методом DAO @Transaction (и HibernateTransactionManager), это, похоже, уже работает. Когда я вызываю send() для JmsTemplate, сообщение отправляется не сразу, а сеанс JMS фиксируется с сеансом Hibernate, когда метод возвращается.

Я не знал, как это возможно без JtaTransactionManager, поэтому я проверил исходный код. Оказывается, что и оболочка для Hibernate, и JmsTemplate регистрируют сеансы с TransactionSynchronizationManager, и сеанс JMS будет зафиксирован, когда сеанс Hibernate будет зафиксирован.

В чем разница между этим и транзакцией JTA. Могу ли я использовать это, чтобы заменить последний??

2 ответа

Решение

Короче говоря, нет, вы не можете получить поддержку для двухфазного принятия без источников данных с поддержкой JTATransactionManager и XA.

То, что вы видите, является координацией двух локальных транзакций, поддерживающих только однофазную фиксацию. Грубо выполняя эту последовательность событий...

  1. Начать JMS-транзакцию
  2. Прочитать сообщение JMS
  3. Начать транзакцию JDBC
  4. Написать в базу данных
  5. Зафиксировать транзакцию JDBC
  6. Подтвердить / подтвердить JMS

Транзакция JMS будет запущена вначале, оборачивая вложенную транзакцию JDBC, так что очередь JMS будет откатываться в случае сбоя фиксации Hibernate/JDBC. Ваш JMS Listener Container должен быть настроен так, чтобы не acknowledge="auto" и вместо этого дождитесь завершения транзакции Hibernate перед отправкой подтверждения.

Если у вас есть только эти два ресурса, то проблема, с которой вам придется столкнуться, заключается в том, когда Hibernate преуспевает в сохранении, тогда вы получите исключение, прежде чем сможете подтвердить JMS-сервер. Не большая проблема, поскольку сообщение JMS не потеряно, и вы прочитаете его снова.

тем не мение

  1. Вы должны написать свой MessageListener для обработки дубликатов сообщений с сервера

  2. Вы также должны обработать сообщение, которое не может быть обработано из-за неверных данных и заканчивается бесконечным циклом попыток его обработать. В этом случае сервер может быть настроен на перемещение сообщения в "мертвую очередь сообщений", или вы сами решаете это в MessageListener

Другие варианты и дальнейшее чтение

Если ваш JMS-сервер не поддерживает XA (глобальные) транзакции, это практически единственное ваше решение.

Если JMS-сервер поддерживает транзакции XA, а JDBC - нет, то вы можете использовать JTATransactionManager и использовать LastResourceCommitOptimisation. Есть JTATransactionManager с открытым исходным кодом, который вы можете использовать как JOTM

Эта статья о JavaWorld более подробно описывает ваше проблемное пространство.

Хотя Брэд подробно ответил на этот вопрос, я бы хотел затронуть очень специфическую часть вашего запроса:

Я не знал, как это возможно без JtaTransactionManager

Из документации Spring:- При обнаружении среды JTA для управления транзакциями будет использоваться Spring JtaTransactionManager.

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-jta.html

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