3
votes

I have a Java SE(!) scenario with JMS and JPA where I might need distributed transactions as well as "regular" JDBC transactions. I have to listen to a queue which sends service requests, persist log on receiving, process the request and update the log after the request has been processed. The message shall only be acknowledged if the request has been processed successfully.

The first idea was to only use JTA (provided by Bitronix). But there I face two problems:

  1. no log will be persisted if the request can't be processed
  2. the request won't be processed if the log can't be updated (unlikely but yet possible)

So the other idea is to create and update the log with regular JDBC transactions. Only the entitymanager(s) for the request transaction(s) would join the user transactions and the entity managers for creating and updating the log would commit directly.

Is it possible to "mix" JTA and JPA on a single persistence unit? Or do we already have patterns for those kinds of JMS and JDBC transactions?

1
Seems to me like it is not really up to if JTA is used or not; you want to use two isolated transactions to do the work. IE. the persisting of logs should be done in their own (nested) transactions. I wouldn't know how to exactly do that using JTA directly, I speak only from the experiences I have while using EJB tech. The persisting of the logs I would do in a REQUIRES_NEW annotated EJB invocation, which creates an isolated nested transaction for that invocation.Gimby
In fact it's three isolated transactions, while the outer one is a JTA user transaction... Nested transactions sounds good, some JTA implementations even support it but they're not part of the JTA standard. Thanks for the hint!Andreas Dolk
Quick research: no nested transactions with bitronix, but: A solution to my question may have been provided with this answer (found by google): stackoverflow.com/a/7674560/105224 suspending a transactionmanager might do the trick.Andreas Dolk
JTA is what is used in EJBs, which have the REQUIRES_NEW propagation. The transaction is not really "nested". The outer transaction is suspended, a brand new transaction is started and committed or rollbacked, then the outer transaction is resumed. If you work in a Java SE environment, I suggest using Spring, which handles that for you.JB Nizet
I'd use spring if I was allowed ;) I only have J2SE, JPA (need to support both hibernate and eclipselink), hornetQ and bitronix. Hope that's enough to reinvent the wheels...Andreas Dolk

1 Answers

2
votes

I actually solved my problem with a slightly different approach. Instead of "mixing" JTA and JDBC transactions I used suspend and resume to work with different user transaction.

The task is still the same: I start a (JTA) user transaction that contains some JMS and JDBC transactions (receiving a message, performing some database operations). And in the middle of that workflow, I want to write a message log but that logging shall not be rolled back when the "outer" transaction fails.

So the solution is, in pseudo code:

 transactionManager.begin()
 doSomeJdbcStuff();
 Transaction main = transactionManager.suspend();

 // do the logging
 transactionManager.begin()  // <- now a new transaction is created and active!
 doSomeLogging();
 transactionManager.commit()

 // continue
 transactionManager.resume(main);
 doSomeMoreJdbcStuff();
 transactionManager.commit();