I see similar problems to: <https://github.com/Jet...
# exposed
g
I see similar problems to: https://github.com/JetBrains/Exposed/issues/1264 and https://github.com/JetBrains/Exposed/issues/1360, they have been open since 2021. Is nested transactions not supported?
The transaction manager exists in
TransactionSynchronizationManager.getResourceMap()
. So the transaction is still open, and in the log I can see this:
Copy code
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.
Hm... I am using two different data sources, both wrapped with
SpringTransactionManager
. 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?
So I guess the problem here is that the
SpringTransactionManager#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.
Copy code
@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.
If I look at the
ThreadLocalTransactionManager
it seems to have better support when creating nested transactions:
Copy code
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?