Spring Transaction Synchronization of JDBC and JMS - java

I have a spring web app running on jboss that is currently configured to use the HibernateTransactionManager for db transactions and the JmsTransactionManager for jms. For jms we use Camel and ActiveMQ, our database is DB2. Within a transaction I need to write a number of records to the database and send two asynchronous jms messages. The jms messages are event notifications and I only want them to be sent if the database transaction commits.
I am willing to accept the risk of the communication with the broker failing after the jdbc transaction has already committed (and thus no messages sent but db committed) so I do not think I need proper XA.
I believe that what I need is "best efforts" transaction management using spring transaction synchronization.
The spring documentation sort of hints at the fact that spring will synchronize the two transactions and commit the jms transaction only after the jdbc transaction has been committed - but I don't think it is very clear. The spring documentation here http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-resource-synchronization doesn't go into enough detail about how it works.
I have found a couple of other sources that say spring will do what I want including some javadoc below, and I have written some integration tests that also show it.
http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/jms/support/JmsAccessor.html#setSessionTransacted%28boolean%29 The javadoc on setSessionTransacted here sounds like exactly what I want.
From what I have seen I think creating the Camel JmsConfiguration with transacted set to true like this is enough:
<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>
However I need to convince someone I work with who is a bit skeptical and thinks that my integration test only works because of a poorly documented side effect rather than a intentional spring feature.
So my question is - Am I correct that spring can be relied upon to synchronize the transactions and always commit the jms transaction after the jdbc transaction or is that not something that I should rely on, and could you point me at any official documentation that says that clearly? And I guess in general is this a good approach to take or should we be managing these transactions in a different way?

This article might be of help Distributed transactions in Spring, with and without XA. I don't think it covers your case specifically - sending message + updating database.

Official Spring Boot repository contain JTA examples that combine JMS with JDBC based on Atomikos, Bitronix or Java EE server JBoss WildFly.
Additionally I also created few examples that are located in my Github repository. This contains also non-Spring Boot (pure Spring) example.

If you are using Local transactions
And the usecase is save to database and then send to jms
Then there could be three cases :
Exception just after receiving(before DB and JMS)
No problem everything will be rolledback
After saving to DB , we have exception
If there is an insert operation,there will be mutiple rows in DB due to retries.With each retry , an insert will be done.And for JMS , message will go to DeadLetterQueue
After saving to DB and sending to JMS , we have an exception
If there is an insert operation,there will be mutiple rows in DB due to retries.With each retry , an insert will be done.And for JMS , message will go to DeadLetterQueue
Now you dont want to use XA, so the solutions could be
1)Check If(message.getJmsRedelivered() {…}
If not , process it
If its redelivered , check if you processed it already
Check if the data is in database based on details in message
Note that re-deliveries are rare so , this check is also rare and there is no overhead
2)If your method is idempotent , then you dont need this check
And regarding XA , XA guarantees that message is delivered only once
And synchronize the transaction across multiple resources
But with XA , you have overhead
So if you can manage without XA , it is preferable

Related

Use case of transaction in Spring AMQP

I am trying to understand Spring AMQP. I can't get my head aroud the transaction.
What is the use case of transaction? Is it similar to JTA? Why would someone rollback a Message?
See the documentation about transaction semantics.
No, it's not "similar to JTA" it applies only to RabbitMQ itself - it can't participate in a global transaction.
One use case:
publish multiple records and one fails - then all are rolled back
i.e. all published records are secured in the broker, or none are.

Spring Boot JMS - when should a message be sent on a #Transacted method?

I was wondering on a Spring Boot method marked as #Transactional, when should a message appear on the queue? I’m asking because I’ve noticed 2 different behaviours on 2 different applications.
Both applications have the following in common:
Spring Boot 2.0 based
JMS message sending is using JmsTemplate, with setSessionTransacted set to true
No explicit transaction settings configured
There is a Mongo DB used (using Spring Data) and a record is being modified in the same method as the message is sent
The major difference between the two applications is:
One has a JPA data source (using Spring Dataj and a record is read and/or written in this method. The other application does not have this data source.
The difference in observed behaviour is that when the JPA source is present, the message is sent at the end of method. Without it, the message is sent immediately.
Is this the expected behaviour?
Can I configure the applications to behave the same way? Ideally I’d like the message to be sent at the end (so any Mongo changes that fail would cancel the message send and rollback any JPA changes made)? I realise that Mongo changes are not part of any transaction created.
Thanks
With JMS and a DB you have two resources.
To have a full transactional behavior you need distributed transactions support.
If you don't have this even when the message is sent as last operation if the sending fails the data is changed in the database anyway.
To configure distributed transaction you need JTA. This is described here:
With JMS and a DB you have two resources. To have a full transactional behavoir you need distributed transactions. We use Bistronix in our application and this works very well.
Have a look at the docs: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-jta.html

Spring Global transaction vs Local transaction

While reading through Spring transaction documentation I see that it supports both Global transactions and Local transactions.
In simple terms what is global transaction and what is local transaction?
What are the advantages of one over the other? What are the appropriate uses of them?
If I use the following configuration – does it mean it is a local transaction?
<tx:annotation-driven transaction-manager="transManager" />
<bean id="transManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
I tried searching both in Google and Stackoverflow, but did not get any resources explaining the same in simple terms.
Actually there are plenty of resources answering your first two questions, for example Spring Documentation explains what local and global transaction is and depicts their differences in chapter 9.2 Motivation. In few words:
Global Transaction is an application server managed transaction, allowing to work with different transactional resources (this might be two different database, database and message queue, etc)
Local Transaction is resource specific transaction (for example Oracle Transactions) and application server has nothing to do with them.
(the same chapter explains the pros and cons of each of them very well and much better then I could explain, so I suggest you to give a closer look)
Answering your later question. The documentation says that JpaTransactionManager is capable for processing global transactions, so by looking at the piece of presented code it's hard to say if it's local or global transaction. The same documentation says that local single-resource transaction DataSourceTransactionManager should be used instead.

How to wrap an object change in my own transaction and incorporate it with Hibernate to JTA?

I have a web-app, which I deploy on Tomcat 6 and it uses Hibernate.
It receives messages on a JMS queue which trigger changes both to my DB, via Hibernate and to an Object of mine (Agent).
The web-requests also access the DB, via Hibernate, and access the shared object (there's a ConcurrentHashMap<AgentId,Agent> held by a singleton).
My problem is that I have a JMS message which changes several different Agents and several tables and I need the changes in the Agents to be available if and only if the DB transaction completed successfully. In addition I do not want to employ read locks as that is too much of a performance hazard for me.
I was thinking of somehow implementing the XAResource interface for my singleton and then use JTA to manage both my singleton and my Hibernate transaction.
What do you think? Does it sound reasonable? Am I way off?
If any additional details are needed please don't hesitate to ask
Ittai
Instead of implementing XAResource, you could use a transactional cache like EHCache which supports JTA since 2.0 (i.e. it can act as an XA resource and participate in a XA transaction alongside other XA resources).

What is the 'best' way to do distributed transactions across multiple databases using Spring and Hibernate

I have an application - more like a utility - that sits in a corner and updates two different databases periodically.
It is a little standalone app that has been built with a Spring Application Context. The context has two Hibernate Session Factories configured in it, in turn using Commons DBCP data sources configured in Spring.
Currently there is no transaction management, but I would like to add some. The update to one database depends on a successful update to the other.
The app does not sit in a Java EE container - it is bootstrapped by a static launcher class called from a shell script. The launcher class instantiates the Application Context and then invokes a method on one of its beans.
What is the 'best' way to put transactionality around the database updates?
I will leave the definition of 'best' to you, but I think it should be some function of 'easy to set up', 'easy to configure', 'inexpensive', and 'easy to package and redistribute'. Naturally FOSS would be good.
The best way to distribute transactions over more than one database is: Don't.
Some people will point you to XA but XA (or Two Phase Commit) is a lie (or marketese).
Imagine: After the first phase have told the XA manager that it can send the final commit, the network connection to one of the databases fails. Now what? Timeout? That would leave the other database corrupt. Rollback? Two problems: You can't roll back a commit and how do you know what happened to the second database? Maybe the network connection failed after it successfully committed the data and only the "success" message was lost?
The best way is to copy the data in a single place. Use a scheme which allows you to abort the copy and continue it at any time (for example, ignore data which you already have or order the select by ID and request only records > MAX(ID) of your copy). Protect this with a transaction. This is not a problem since you're only reading data from the source, so when the transaction fails for any reason, you can ignore the source database. Therefore, this is a plain old single source transaction.
After you have copied the data, process it locally.
Setup a transaction manager in your context. Spring docs have examples, and it is very simple. Then when you want to execute a transaction:
try {
TransactionTemplate tt = new TransactionTemplate(txManager);
tt.execute(new TransactionCallbackWithoutResult(){
protected void doInTransactionWithoutResult(
TransactionStatus status) {
updateDb1();
updateDb2();
}
} catch (TransactionException ex) {
// handle
}
For more examples, and information perhaps look at this:
XA transactions using Spring
When you say "two different databases", do you mean different database servers, or two different schemas within the same DB server?
If the former, then if you want full transactionality, then you need the XA transaction API, which provides full two-phase commit. But more importantly, you also need a transaction coordinator/monitor which manages transaction propagation between the different database systems. This is part of JavaEE spec, and a pretty rarefied part of it at that. The TX coordinator itself is a complex piece of software. Your application software (via Spring, if you so wish) talks to the coordinator.
If, however, you just mean two databases within the same DB server, then vanilla JDBC transactions should work just fine, just perform your operations against both databases within a single transaction.
In this case you would need a Transaction Monitor (server supporting XA protocol) and make sure your databases supports XA also. Most (all?) J2EE servers comes with Transaction Monitor built in. If your code is running not in J2EE server then there are bunch of standalone alternatives - Atomicos, Bitronix, etc.
You could try Spring ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html that supports distributed db transaction. This could be a better alternative to XA

Categories