Jonathan
Jonathan

Reputation: 2776

@Transactional not working on JNDI Datasources

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

Answers (0)

Related Questions