Spring transaction JMSTemplate in the @Transactional method
In our Spring Boot application, we have a paging loop on the database that will send a JMS message for each page using JMSTemplate
. The method to include loops is @Transactional
. JMSTemplate
is created with the transaction flag set to true.
I’ve been going through the source code of JMSTemplate
and as far as I know, if there’s already an external transaction in progress, it doesn’t commit the transaction session, but it puts it into that transaction
Now let’s consider the following code:
@Transactional
public void loopThroughPages(String destination, String from, String to) {
Pageable pageRequest = PageRequest.of(0, maxPageSize);
Page<Event> eventPage;
do {
eventPage = eventRepo.getEventsInTimeRangeForDestination(from, to, destination, pageRequest);
if(eventPage.hasContent()) {
Message<String> eventMessage = buildEventMessage(eventPage.getContent());
JmsTemplate template = queueService.createTemplate(destination);
template.send(eventMessage);
pageRequest = eventPage.nextPageable();
}
} while(pageRequest != null && eventPage.hasNext());
}
createTemplate
uses CachingConnectionFactory
and setSessionTransacted
to create a DynamicJmsTemplate
to true
I’m not entirely sure right now how this translates into trading. My understanding is that all N page messages are sent in a transaction created from loopThroughPages, and once the loopThroughPages
method completes, it will commit all
N
messages, not after each message is sent. This also means that transactions on the MQ side will remain open until the last page is processed. Is this understanding correct?
Solution
The key point here is trade management.
If you use an XA data source and configure it on your spring boot application, you will have a distributed transaction and the commit/rollback of your transaction will be managed by spring because you have a method annotated with @Transactional, otherwise you will have local transaction management and transactions for your database and messaging system will not be synchronized.
For sending messages, you can configure whether the message is
persisted through properties, which means whether your message is persisted by your messaging system, and from the listener’s perspective, you can configure the acknowledgment mode.
By the way, my advice is to let Spring manage the transactions and everything will be fine, but the real caveat is that if you want distributed transactions between the database and the JMS system, you just need to configure it atomikos to be an available option, otherwise it doesn’t have to manage transactions manually, let Spring manage it for you.
Hope that helps