Spring синхронизирует транзакции Hibernate и JMS
Я работаю над автономным приложением, которое использует JMS и Hibernate.
Документация предлагает использовать JTA, если я хочу, чтобы транзакции проходили через оба ресурса.
Однако сейчас, с аннотированным методом DAO @Transaction (и HibernateTransactionManager), это, похоже, уже работает. Когда я вызываю send() для JmsTemplate, сообщение отправляется не сразу, а сеанс JMS фиксируется с сеансом Hibernate, когда метод возвращается.
Я не знал, как это возможно без JtaTransactionManager, поэтому я проверил исходный код. Оказывается, что и оболочка для Hibernate, и JmsTemplate регистрируют сеансы с TransactionSynchronizationManager, и сеанс JMS будет зафиксирован, когда сеанс Hibernate будет зафиксирован.
В чем разница между этим и транзакцией JTA. Могу ли я использовать это, чтобы заменить последний??
2 ответа
Короче говоря, нет, вы не можете получить поддержку для двухфазного принятия без источников данных с поддержкой JTATransactionManager и XA.
То, что вы видите, является координацией двух локальных транзакций, поддерживающих только однофазную фиксацию. Грубо выполняя эту последовательность событий...
- Начать JMS-транзакцию
- Прочитать сообщение JMS
- Начать транзакцию JDBC
- Написать в базу данных
- Зафиксировать транзакцию JDBC
- Подтвердить / подтвердить JMS
Транзакция JMS будет запущена вначале, оборачивая вложенную транзакцию JDBC, так что очередь JMS будет откатываться в случае сбоя фиксации Hibernate/JDBC. Ваш JMS Listener Container должен быть настроен так, чтобы не acknowledge="auto"
и вместо этого дождитесь завершения транзакции Hibernate перед отправкой подтверждения.
Если у вас есть только эти два ресурса, то проблема, с которой вам придется столкнуться, заключается в том, когда Hibernate преуспевает в сохранении, тогда вы получите исключение, прежде чем сможете подтвердить JMS-сервер. Не большая проблема, поскольку сообщение JMS не потеряно, и вы прочитаете его снова.
тем не мение
Вы должны написать свой MessageListener для обработки дубликатов сообщений с сервера
Вы также должны обработать сообщение, которое не может быть обработано из-за неверных данных и заканчивается бесконечным циклом попыток его обработать. В этом случае сервер может быть настроен на перемещение сообщения в "мертвую очередь сообщений", или вы сами решаете это в 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