I'm using Spring-tx-4.0.9 in a multithreaded application and have a problem with "stalled" transaction after the thread is killed by OutOfMemory.
Each thread ask PlatformTransactionManager
(implementation org.springframework.jdbc.datasource.DataSourceTransactionManager
) to get an transaction via TransactionTemplate
Propagation is REQUIRED. This template has a timeout set. State of a transaction is managed by application and after all, work is done, then thread calls commit. This returns a transaction back to the PlatformTransactionManager
, and almost every time releases connection to the DB (in DB, the session for this connection is mostly released)
But if the thread is killed by OutOfMemory, then the underlying transaction is returned to internal transaction pool and another thread can acquire this "broken" transaction. This transaction has the timeout set from the first time and cannot be reset even if new thread call TM to get transaction with new TransactionTemplate
. So after this timeout expires, every request on transaction throws TransactionTimedOutException
.
Only available methods on PlatformTransactionManager
are getTransaction
, commit
and rollback
.
Method getTransaction
can return new or previous transaction. From returned instance of TransactionStatus
, I'm able to detect new or stalled transaction, but I'm unable to release it.
Method rollback
sets flag isRollbackOnly
, but the transaction is still not released and getTransaction
returns stalled. If I then call commit
as recommended by JavaDoc, then nothing changed and the transaction is still hanged.
If I use propagation REQUIRES_NEW
, then "broken" transaction is suspended, which solve a problem with TransactionTimedOutException
, but an old transaction is still hanged and holds the connection to the DB (unwanted state).
Is there a way, how to proper release a broken transaction (rollback and release connection)?
EDIT- Current code for getting a TransactionalStatus
public TransactionStatus beginTransaction() {
// transaction begin
logger.debug("Create new transaction.");
TransactionTemplate template = new TransactionTemplate(transactionManager);
template.setTimeout(txConnectionTimeout);
TransactionStatus txStatus = transactionManager.getTransaction(template);
logger.debug(
"Transaction created. TransactionStatus: isCompleted=" + txStatus.isCompleted() + ", isNewTransaction=" +
txStatus.isNewTransaction());
return txStatus;
}