Весенняя синхронизация транзакций JDBC и JMS - PullRequest
16 голосов
/ 10 февраля 2012

У меня есть весеннее веб-приложение, работающее на jboss, которое в настоящее время настроено на использование HibernateTransactionManager для транзакций в БД и JmsTransactionManager для jms. Для jms мы используем Camel и ActiveMQ, нашей базой данных является DB2. В рамках транзакции мне нужно записать несколько записей в базу данных и отправить два асинхронных сообщения JMS. Сообщения jms являются уведомлениями о событиях, и я хочу, чтобы они отправлялись только в случае фиксации транзакции базы данных.

Я готов принять риск сбоя связи с брокером после того, как транзакция jdbc уже зафиксирована (и, следовательно, нет сообщений, отправленных, но db зафиксирован), поэтому я не думаю, что мне нужен правильный XA.

Я считаю, что мне нужно управление транзакциями «из лучших сил» с использованием весенней синхронизации транзакций.

Документация Spring намекает на то, что spring синхронизирует две транзакции и зафиксирует транзакцию jms только после фиксации транзакции jdbc, но я не думаю, что это очень ясно. В весенней документации здесь http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-resource-synchronization недостаточно подробно описано, как она работает.

Я нашел несколько других источников, в которых говорится, что Spring будет делать то, что я хочу, включая некоторые javadoc ниже, и я написал несколько интеграционных тестов, которые также показывают это.

http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/jms/support/JmsAccessor.html#setSessionTransacted%28boolean%29 Javadoc для setSessionTransacted здесь звучит как то, что я хочу.

Из того, что я видел, я думаю, что достаточно создать Camel JmsConfiguration с установленным значением true, как это:

<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="transacted" value="true"/>
    <property name="concurrentConsumers" value="10"/>
</bean>

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

Так что мой вопрос - я прав, что на пружину можно положиться, чтобы синхронизировать транзакции и всегда фиксировать транзакцию jms после транзакции jdbc, или это не то, на что я должен положиться, и не могли бы вы указать мне на любого чиновника? документация, которая говорит это ясно? И я полагаю, что в целом это хороший подход или мы должны управлять этими транзакциями по-другому?

Ответы [ 3 ]

3 голосов
/ 10 февраля 2012

Эта статья может быть полезна Распределенные транзакции в Spring с XA и без нее . Я не думаю, что это конкретно касается вашего дела - отправка сообщения + обновление базы данных.

1 голос
/ 12 июля 2015

Официальный репозиторий Spring Boot содержит примеры JTA, которые объединяют JMS с JDBC на основе Atomikos , Битроникс или Сервер Java EE JBoss WildFly .

Кроме того, я также создал несколько примеров, которые находятся в моем хранилище Github . Здесь также содержится пример не Spring Boot (чистый Spring).

0 голосов
/ 24 декабря 2016

Если вы используете Локальные транзакции, а вариант использования сохраняется в базу данных, а затем отправляется в jms

Тогда может быть три случая:

  1. Исключение только после получения (до БДи JMS)

Нет проблем, все будет откат

После сохранения в БД у нас возникает исключение

Если есть операция вставки, в БД будет несколько строк из-за повторных попыток. При каждой повторной попытке вставкабудет сделано. А для JMS сообщение будет отправлено в DeadLetterQueue

После сохранения в БД и отправки в JMS у нас возникает исключение

Если есть операция вставки, в БД будет несколько строк из-за повторных попыток. При каждой повторной попытке вставка будетбудет сделано. А для JMS сообщение будет отправлено в DeadLetterQueue

Теперь вы не хотите использовать XA, поэтому решения могут быть

1) Проверьте, если (message.getJmsRedelivered () {…}

Если нет, обработайте его

Если он доставлен, проверьте, обработали ли вы его уже

Проверьте, если данныев базе данных на основе деталей в сообщении

Обратите внимание, что повторные поставки редки, поэтому эта проверка также редка и нет накладных расходов

2) Если ваш метод идемпотентен, то вам не нужноэта проверка

А что касается XA, XA гарантирует, что сообщение доставляется только один раз, и синхронизирует транзакцию между несколькими ресурсами

Но с XA у вас есть издержки

Так что если вы можетеобойтись без XA, предпочтительнееле

...