Bean-Managed Transaction Suspension in J2EE
As you can see, with the help of the
TransactionManager interface, you can extend the
standard functionality provided by UserTransaction and
achieve in BMT code the same level of flexibility available for CMT
beans.
One non-obvious thing to remember is that when a transaction is
suspended, it doesn't mean that the transactional timer is stopped.
In other words, if the transaction timeout was set to 30 seconds
and then transaction was suspended for 20 seconds and resumed, the
transaction would have only ten seconds left to run before timeout.
Transaction suspension simply disassociates a transaction with the
running thread, and the resume() call associates it
back without affecting the transactional timeout timer.
Known Issues
Because the J2EE specification doesn't require the availability and
functionality of TransactionManager in J2EE containers
(although we know that it should be there because of underlying JTA
infrastructure), there are a few issues that exist in some
application servers. For example, one particularly strange anomaly
exists in WebLogic versions 7, 8, and 9 (beta): if a transaction
was marked for rollback (by calling
UserTransaction.setRollbackOnly()) and then suspended,
attempting to resume the suspended transaction will fail with:
javax.transaction.InvalidTransactionException: Attempt to
resume an inactive transaction
The following code illustrates this behavior.
...
// obtain UserTransaction object and start transaction
InitialContext ctx = new InitialContext();
UserTransaction userTransaction = (UserTransaction)
ctx.lookup("java:comp/UserTransaction");
userTransaction.begin();
// mark for rollback
userTransaction.setRollbackOnly();
TransactionManager tm = getTransactionManager();
// suspend transaction
Transaction transaction = tm.suspend();
// resume suspended transaction
// this call will fail with InvalidTransactionException
// in WebLogic
tm.resume(transaction);
...
Fortunately, there is a workaround for this particular problem.
WebLogic's implementation of TransactionManager, along
with the standard resume(Transaction transaction)
method, has a forceResume(Transaction transaction)
method that can be used instead. The code below demonstrates the
pattern that should be used when your code is running in WebLogic.
Note that in this case, the reference to
TransactionManager should be cast to WebLogic's custom
implementation interfaces (
weblogic.transaction.TransactionManager in WebLogic 7 or
weblogic.transaction.ClientTransactionManager in
WebLogic 8 and above).
...
// obtain UserTransaction object and start transaction
InitialContext ctx = new InitialContext();
UserTransaction userTransaction = (UserTransaction)
ctx.lookup("java:comp/UserTransaction");
userTransaction.begin();
// mark for rollback
userTransaction.setRollbackOnly();
TransactionManager tm = getTransactionManager();
// suspend transaction
Transaction transaction = tm.suspend();
// resume suspended transaction
try {
// first try standard JTA call
tm.resume(transaction);
}
catch (InvalidTransactionException e) {
// standard method failed, try forceResume()
if (tm instanceof
weblogic.transaction.ClientTransactionManager) {
// WebLogic 8 and above
((weblogic.transaction.ClientTransactionManager)tm)
.forceResume(transaction);
}
else if (tm instanceof
weblogic.transaction.TransactionManager) {
// WebLogic 7
((weblogic.transaction.TransactionManager)tm)
.forceResume(transaction)
}
else {
// cannot resume
throw e;
}
}
...
Prev [1] [2] [3] [4] Next