We have Multiple Tomcat providing web services for our internal product.
Tomcat, Active MQ servers are different
Web services call sequence
Tomcat Receive request
Start DB Transaction (Spring Transaction)
Execute some business logic
Generate certain events & push in queue (Active MQ)
Start JMS Transaction
Push in queue
Commit JMS
Execute other business logic
(other business logic may generate another event for JMS)
Commit DB.
So what i want is to start Global Transaction which should take care of committing respective transaction in sequence.
JMS should only get commit if DB is getting commit.
Is it possible with JTA??????
Your suggestions are welcome.
Yes. See these posts:
Configuring Spring and JTA without full Java EE
Configuring ActiveMQ transactions in Spring
Related
I am migrating a Spring boot app running on a JEE app server which makes use of JTA to coordinate JMS and JPA transactions:
Exceptions raised while processing a message trigger a JPA and JMS roll-backs (i.e. message goes back to the originating queue)
If all database operations are successful, and, the message is successfully moved to the next queue, JPA and JMS transactions are both committed
The target environment does not support JTA.
I am looking for guidance on how to setup transaction managers so that:
a JPA transaction is started immediately after starting the JMS transaction
a JPA transaction is concluded just before terminating the JMS transaction
a failure of terminating the JPA transaction would fail the JMS transaction
Any documentation or sample code would be awesome.
Many thanks in advance
A possible way forward for this scenario where none of the resources support XA or JTA:
JMS provider
Database driver
... is to use a "bracketing" transaction manager configured to run two transactions. At high level, steps are as specified in Dave Syer's article
Start messaging transaction
Receive message
Start database transaction
Update database
Commit database transaction
Commit messaging transaction
The Spring Data project provides such a transaction manager: see ChainedTransactionManager .
This strategy works well when the error occurs in committing the database transaction, i.e. step 5. For cases where the error happens in the JMS commit, i.e. step 6, one will end up with the message in dead-letter.
Testing this implementation with 100,000 messages showed that about 0.005 % message end up in dead letter. For some, the error occurred when committing the JPA transaction, some for JMS.
For the system to be operable, messages in dead-letter should be retriable regardless of the point of failure. This means that the bracketing transaction manager option is only viable if the app is changed to implement idempotency: keep a trace of the JMS Message IDs already processed. The app has to skip the update part, step 4, for when the JMS Message ID was already processed.
What is the most elegant way to consume multiple JMS messages in a single transaction in Spring Integration without storing the message again in an Aggregator backed by a persistent Message Store?
In an previous project based on IBM Integration Bus this feature (IBM calls it Commit Count) was very helpful to increase message throughput.
See the Spring Batch BatchMessageListenerContainer.
Here is the flow:
Begin Transaction.
Message put into the queue but not ready to be dequeue. (Right now I don't know how to achieve it)
(i)End Transaction - Successful: Message will be available to be dequeue.
(ii) Rollback: Message will be removed from queue.
Message successfully de-queue by the Listener.
I can configure Spring Transaction Manager for hibernate entities. Same way I can Active MQ available for JMSTransactionManager. But the big question is How would JMSTransactionManager will know the state of HibernateTransactionManager? How would these two interact?
Note: I am using Tomcat managed datasources for Hibernate entities. Apache Camel support is also available in project.
You need an XA-enabled transaction manager, and Spring doesn't come with any. So either deploy your app in a Java EE application server, or embed a stand-alone transaction manager like Bitronix.
I'm using Oracle 11g for my database and its Oracle Streams AQ feature as JMS implementation.
For all I know, it should be possible to implement a Spring based message-driven POJO (MDP) that uses the same data source for both transactional data access and JMS transactions -- all without XA-Transactions (IIRC, this was marketed as a feature of SpringSource Advanced Pack for Oracle).
Is this possible using Hibernate as well? Ideally, my MDP would start a JMS transaction and read a message from a queue, then re-use the transaction for data access through Hibernate. If anything goes wrong, the JMS and database transaction would both be rolled back, without using 2-phase commit (2PC).
I'm not much of a transaction guru, so before I start digging deeper, can anyone confirm that this is possible and makes sense as well?
Update:
What I want is an implementation of the Shared Transaction Resource pattern. The sample code demonstrates it for ActiveMQ and JDBC, but I need to use Oracle Streams AQ and Hibernate.
Update2:
The SpringSource Advanced Pack for Oracle has been open sourced as part of Spring Data JDBC and it "provides the option of using a single local transaction manager for both
database and message access without resorting to expensive distributed 2-phase commit
transaction management".
2PC shouldn't be necessary, as you say, since the appserver should take care of it. However, you'll pretty much have to use JTA (i.e. JavaEE container) transactions, rather than vanilla DataSource transactions, since JMS only works with JTA.
This isn't a big deal, it's just a bit more fiddly:
Your Spring config should use
<jee:jndi-lookup/> to get a
reference to your container's
DataSource, and you inject that
data source into your spring-managed
hibernate SessionFactory.
You then need to introduce a transaction manager into the context (<tx:jta-transaction-manager/> should work in most app-servers).
In your Spring JMS MessageListenerContainer, plug the above transaction manager reference into it.
Does that all make sense, or should I elaborate? This setup should ensure that the container-managed transactions are held across JMS and Hibernate interactions.
I have a process which involves sending a JMS message.
The process is part of a transaction.
If a later part of the transaction fails, a part that is after a previous part that sent the message, I need to cancel the message.
One thought I had was to somehow set on the message that it is not to be picked up for a certain amount of time, and if I need to rollback, then I could go and cancel the message.
Not knowing messaging, I do not know if the idea is possible.
Or, is there a better idea?
Thanks
You can use JMS and JTA (Java Transaction API) together. When doing that, the sending of a JMS message or the consumption of a received message actually happens atomically as part of the transaction commit.
What does this mean? If the transaction fails or is rolled back, the "sent" message doesn't go out and any "received" messages aren't really consumed. All handled for you by your JMS and JTA provider.
You need to be using a JMS implementation that supports JTA. Sounds like you're already using transactions, so it might be a matter of doing some configuration to make it happen (waving hand vigorously...).
I've had experience using this (BEA WebLogic 7 w/ BEA WebLogic Integration). Worked as advertised -- "the outside world" saw no impact of JMS stuff I tried unless the transaction committed successfully.
Earlier versions of this linked to a Java page describing JMS/JTA integration generally. The page went stale and I don't see an equivalent replacement. This javadoc is for a JMS interface related to this capability.
What you have described is an XA transaction. This allows a transaction to scope across multiple layers i.e. JMS provider, DB or any other EIS. Most containers can be configured to use both non XA and none XA transaction so check your container settings!
For example if you are using JMS with XA transactions the following is possible.
Start Transaction
|
DB Insert
|
Send JMS Msg
|
More DB Inserts
|
Commit Transaction <- Only at this point will the database records be inserted and the JMS message sent.
XA Tranactions are only available in full Java EE containers so XA transactions are not available in Tomcat.
Good luck!
Karl