I'm having trouble finding a simple example of a JTA transaction spanning multiple resources (e.g. two databases, a database and a JMS queue, etc.)
I've spent a lot of time reading up on this and have working samples of doing a JTA transaction with a JMS queue, and a JTA transaction over a JDBC database driver. I just can't seem to find anything on making both the JMS queue and the JDBC database part of the same JTA transaction.
Can anyone provide a brief sample or a link to something that does demonstrate how to use the JTA API for this purpose?
For a JTA transaction to coordinate amongst JMS and JDBC resources, the following is required:
XAConnectionFactory - a JMS XA-compliant connection factory must be available in JNDI; the specific one to use depends on your application server/container.
XA-compliant JDBC driver - the driver must be XA, most databases provide one, and the connection must support READ_COMMITTED isolation level, anything less won't be sufficient.
Aside from that, if you're using an app server, the container will handle transactions automatically if you're using message driven beans and XA-compliant drivers.
Check these links for exmaples:
http://blog.inflinx.com/2010/04/08/spring-jta-jpa-jms/
http://www.oracle.com/technetwork/java/faq-140431.html#relship_transac
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.
TLDR:
1.Where does atomikos keep its trasnaction records so it can function and how is it best to "secure" them against losing/corrupting them. I use Docker/Docker-Compose and Spring Boot.
2.If the app dies unexpectdly, do all the transactions roll back because atomikos automagically started the appropiate SQL/JMS transactions with the sources?
Details
Hello.
I am starting to use atomikos in Spring Boot to enable XA transactions (in my case simply one datasource and an ActiveMQ/JMS broker.
I have been Googling and can't find a more "in depth" blog or site that explains in a bit more details how Atomikos works under the hood.
I do see the atomikos transaction logs in the form:
{"id":"127.0.1.1.tm159765570032300035","wasCommitted":true,"participants":[{"uri":"127.0.1.1.tm35","state":"COMMITTING","expires":1597655710327,"resourceName":"dataSource"},{"uri":"127.0.1.1.tm36","state":"COMMITTING","expires":1597655710327,"resourceName":"jmsConnectionFactory"}]}
I can only assume these are simply actual "logs" and not like the kafka.db file in say ActiveMQ when using file persistence.
Questions
So does atomikos keep its state in memory?
If say an unexpected shutdown occurred half way through an XA transaction, will all the JTA sources simply rollback?
If the atomikos state is held in a file/database somewhere...are there some best practices when using docker-compose for example?
Example:
A #Component picks out a database entity "REQUIRES_PROCESSING" for queuing on to a JMS queue and then switches the entity to "PROCESSING".
The JMS message is queued but then the App unexpectedly dies before the database entity is set to "PROCESSING".
Will in this case, atomikos has now no state (it died with the app) but it created a SQL and ActiveMQ trasnaction that will simply timeout and everything rolls back?
The application reboots 5 seconds later...what happens here? Is this transaction picked up again somehow (i.e. atomikos has still got state somewhere?).
Will the rebooted app just grab the rolledback entity and simply retry as expected?
Are there any pitfalls here?
Thank you for any claification.
I am trying to understand in background how transaction is mapped to jdbc connection i.e one jdbc connection can be parallely used for multiple spring transactions at the same time or one connection is totally reserved for one transaction at a given time and only released after transaction is complete.
I my opionion one of the best way to understanding how Spring managed transactions is reading Transaction Management Reference Doc.
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