Reputation: 2776
we have a webapp running on wildfly, using JNDI datasources to handle database related operations. During a modernization operation, we are currently changing EJBs to Spring as a first step to make the application capable of running on a simpler servlet container like tomcat.
After changing the beans from @EJB
to @Service
and obviously changing the @Transactional
annotations from the jakarta
namespace to the spring
annotations, our transaction behaviour is suddenly broken.
As part of a testsuite, we habe a testcase which roughly does the following
// Within a @Transactional(REQUIRED) block
Connection con = getConnection(...) (1)
// do some sql updates (2)
try {
// Start @Transactional(REQUIRES_NEW) block
Connection con2 = getConnection(...) (3)
// do some more sql updates (4)
throw new Exception();
// End REQUIRES_NEW block
} catch (Exception ignored) {
}
// End Required block
The expectation would be, that our test case ends up with the sql updates from (2) being visible in the database, the sql updates from (4) not being visible, as connection con2 should execute within a different transaction which should have been rolled back upon the exception.
However, the inner updates at (4) will consistently be written in the outer transaction. No rollbacks occur. From the looks of it, con and con2 are the same object or at least reference to the same underlying Wildfly transaction. And just for the reference: If all bean and transactionannotations are switched back to jakarta annotations, it works.
Also, we verified that the inner code block actually does open/close a transaction. The block is a callback, executed in a separate spring bean annotated with @Transactional
. We can see that this results in a spring-proxy being built around the service and we can see, that after completing/aborting the code a commit/rollback is executed on the JbossWrappedDatasource.
So, our assumption is, that (3) is not aware of the newly started transaction and gives us the outer transactionobject. So we looked at the code obtaining the transaction. Initially this was some lookup done with the javax.InitialContext
. We assumed, that a Spring related lookup might do the trick and switched to the JndiDataSourceLookup
from Spring and when that didn't do the trick, we also put the resulting Datasource
through the DataSourceUtils
class from Spring.
What did we do wrong? How can we obtain a second connection bound to the inner transaction context?
Edit
We have some suspicion about the reason. It seems that spring refuses to open a transaction, once there is an open connection.
Upvotes: 0
Views: 26