Gustav Elmgren
01/09/2023, 12:42 PMGustav Elmgren
01/09/2023, 3:44 PMTransactionSynchronizationManager.getResourceMap()
.
So the transaction is still open, and in the log I can see this:
2023-01-09 16:41:42.332 TRACE 108391 --- [nio-5000-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [service.ServiceOne.nestedServiceCallWithTransactional]
2023-01-09 16:41:42.332 DEBUG 108391 --- [nio-5000-exec-4] o.j.e.spring.SpringTransactionManager : Initiating transaction commit
2023-01-09 16:41:42.350 DEBUG 108391 --- [nio-5000-exec-4] o.j.e.spring.SpringTransactionManager : Releasing JDBC Connection [HikariProxyConnection@2012876927 wrapping org.postgresql.jdbc.PgConnection@5016f1a] after transaction
2023-01-09 16:41:42.351 DEBUG 108391 --- [nio-5000-exec-4] o.j.e.spring.SpringTransactionManager : Resuming suspended transaction after completion of inner transaction
2023-01-09 16:41:42.351 TRACE 108391 --- [nio-5000-exec-4] o.s.t.i.TransactionInterceptor : Completing transaction for [service.ServiceTwo.outerServiceCall]
2023-01-09 16:41:42.351 DEBUG 108391 --- [nio-5000-exec-4] o.j.e.spring.SpringTransactionManager : Initiating transaction commit
2023-01-09 16:41:42.352 DEBUG 108391 --- [nio-5000-exec-4] o.j.e.spring.SpringTransactionManager : Initiating transaction rollback after commit exception
So it it aware that it is a nested transaction, and it resumes the outer transaction. But for some reason it does complete the transaction right away when resuming it, but it is in the middle of execution in the outer service method.Gustav Elmgren
01/09/2023, 4:46 PMSpringTransactionManager
. Given that the SpringTransactionManager
has a static key SPRING_TX_KEY
, so when the inner tx is cleaning up, it will use that key to cleanup, and thus create problems for the outer transaction?Gustav Elmgren
01/09/2023, 4:53 PMSpringTransactionManager#doCleanupAfterCompletion
1. Remove the resource, via the SPRING_TX_KEY
, so when the outer transaction trying to do the cleanup, the resource is already removed
2. It also reset the manager, via TransactionManager#resetCurrent
, not who is responsible for putting back the old transaction manager.
If I take the code from SpringTransactionManager
but provide a unique key, and also save the the manager it all seems to work.
@Transactional(readOnly=true)
fun outerTransaction() {
//Do some read only stuff
val tmp = TransactionManager.manager
myOtherSerivce.innerTransaction() //Given this will call `resetCurrent` with null
TransactionManager.resetCurrent(tmp)
}
//MyOtherService
@Transactional(transactionManager="write")
fun innerTransaction() { ... }
I'm not sure if my scenario is just plain dumb, or if the SpringTransactionManager
is missing something.Gustav Elmgren
01/09/2023, 5:08 PMThreadLocalTransactionManager
it seems to have better support when creating nested transactions:
val existingForDb = db?.transactionManager
existingForDb?.currentOrNull()?.let { transaction ->
val currentManager = outer?.db.transactionManager
try {
TransactionManager.resetCurrent(existingForDb)
transaction.statement().also {
if (db.useNestedTransactions) {
transaction.commit()
}
}
} finally {
TransactionManager.resetCurrent(currentManager)
}
So it does assign the current inner, and when it is finished it does put back the outer. Should not this be done in SpringTransactionManager
also?