Синхронизация транзакций Spring JDBC и JMS

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

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

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

Документация spring намекает на тот факт, что spring синхронизирует две транзакции и фиксирует транзакцию jms только после того, как транзакция jdbc была зафиксирована, но я не думаю, что это очень ясно. Документация Spring здесь 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#setSessionTranscted%28boolean%29 Документация javadoc на setSessionTranscted здесь звучит именно так, как я хочу.

Из того, что я видел, я думаю, что создания 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>

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

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


person laurie    schedule 10.02.2012    source источник
comment
Привет, уже есть ответ на свой вопрос?   -  person snowindy    schedule 16.05.2013
comment
Привет, нет, не совсем. Я до сих пор не видел действительно четкой документации, чего я хотел, но теперь мы используем ее в производстве без каких-либо проблем.   -  person laurie    schedule 16.05.2013


Ответы (3)


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

person gkamal    schedule 10.02.2012
comment
Спасибо, я читал эту статью пару раз. В разделе Best Efforts 1PC они предоставляют два примера весенней синхронизации, но в одном они настраивают TransactionAwareConnectionFactoryProxy, а в другом - ChainedTransactionManager. Если мне не нужно выполнять какие-либо дополнительные настройки для получения того же результата, я бы предпочел этого не делать. - person laurie; 12.02.2012

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

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

person luboskrnac    schedule 12.07.2015
comment
Ссылка на ваш репозиторий Git больше не действительна. - person Derek Mahar; 23.12.2016

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

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

  1. Исключение сразу после получения (до DB и JMS)

Без проблем все откатится

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

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

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

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

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

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

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

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

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

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

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

Но с XA у вас есть накладные расходы

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

person Ruchi Saini    schedule 24.12.2016
comment
Я не мог понять ваши 2 балла. Я понял, что если после сохранения в дБ у нас будет исключение, тогда произойдет откат дБ, а также сообщение jms будет откатано. Это правильно? - person Vishal Patel; 02.06.2020