Вопрос по jms, java, spring, transactions, hibernate – Spring синхронизирует транзакции Hibernate и JMS
Я работаю над автономным приложением, которое использует JMS и Hibernate.
В документации предлагается использовать JTA, если я хочу, чтобы транзакции проходили через оба ресурса.
Однако сейчас, с аннотированным методом DAO @Transaction (и HibernateTransactionManager), это, похоже, уже работает. Когда я вызываю send () для JmsTemplate, сообщение отправляется не сразу, а сеанс JMS фиксируется с сеансом Hibernate, когда метод возвращается.
Я не знал, как это возможно без JtaTransactionManager, поэтому я проверил исходный код. Оказывается, что и оболочка для Hibernate, и JmsTemplate регистрируют сеансы с помощью TransactionSynchronizationManager, и сеанс JMS будет зафиксирован при фиксации сеанса Hibernate.
В чем разница между этой транзакцией и транзакцией JTA. Могу ли я использовать это, чтобы заменить последний ??
Короче говоря, нет, вы не можете получить поддержку двухфазной фиксации без источников данных с поддержкой JTATransactionManager и XA.
То, что вы видите, является координацией двухLocal Transactions поддержка только однофазного коммита. Грубо выполняя эту последовательность событий ...
Start JMS Transaction Read JMS message Start JDBC Transaction Write to database Commit JDBC Transaction Commit/Acknowledge JMSТранзакция JMS будет запущена вначале, оборачивая вложенную транзакцию JDBC, так что очередь JMS будет откатываться в случае сбоя фиксации Hibernate / JDBC. Ваш JMS Listener Container должен быть настроенnot to acknowledge="auto"
и вместо этого дождитесь завершения транзакции Hibernate перед отправкой подтверждения.
Если у вас есть только эти два ресурса, то проблема, с которой вам придется столкнуться, заключается в том, когда Hibernate преуспевает в сохранении, тогда вы получите исключение, прежде чем сможете подтвердить JMS-сервер. Не большая проблема, поскольку сообщение JMS не потеряно, и вы прочитаете его снова.
However
You must write your MessageListener to handle duplicate messages from the server
You must also handle a message that cannot be processed due to bad data and ending up in an infinite loop of trying to comsume it. In this case the server may be configured to move the message to a "dead message queue", or you deal with this yourself in the MessageListener
Other options and further reading
Если ваш JMS-сервер не поддерживает XA (глобальные) транзакции, это практически единственное ваше решение.
Если JMS-сервер поддерживает транзакции XA, а JDBC - нет, то вы можете использовать JTATransactionManager и использоватьLastResourceCommitOptimisation, Есть JTATransactionManager с открытым исходным кодом, который вы можете использовать как JOTM
Эта статья о JavaWorld подробнее расскажет о вашем проблемном пространстве.
Хотя Брэд подробно ответил на этот вопрос, я бы хотел затронуть очень специфическую часть вашего запроса:
I didn't know how this is possible without the JtaTransactionManager
Из весенней документации: - When a JTA environment is detected, Spring’s JtaTransactionManager will be used to manage transactions
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-jta.html