Pitfalls with UserTransaction.setTransactionTimeout

First and foremost, UserTransaction.setTransactionTimeout1 affects only subsequent2 transactions associated with the current thread. This behavior is explicitly stated in the documentation, but may not be intuitively expected. However, if we think about this behavior, it becomes obvious that if the method were affecting transactions started by other threads, then setting a transaction timeout would have been inherently racy3: another thread could have called UserTransaction.setTransactionTimeout with a different timeout concurrently with the current thread calling UserTransaction.setTransactionTimeout and UserTransaction.begin. In such a situation it would have been impossible to predict the timeout value for the transaction started by the current thread.

Another surprise is that calling a method of an enterprise bean that uses container-managed transactions may result in loosing the timeout set via UserTransaction.setTransactionTimeout if the method of the enterprise bean starts a transaction and the transaction timeout configured for this method/bean is different from what you set via UserTransaction.setTransactionTimeout. This of course depends on the implementation of Jakarta Enterprise Beans that is being used. Following is the code provided as an example where I experienced the described unexpected behavior with Oracle WebLogic Server.

// checkSomething starts a new transaction with the timeout 2 seconds
if (myBeanWithContainerManagedTransactions.checkSomething(2)) {
    // Instead of the expected timeout of 10 seconds,
    // this call starts a transaction with the timeout of 2 seconds.

In order to avoid this potential problem, one should always call UserTransaction.setTransactionTimeout right before2 calling UserTransaction.begin, or, even better, use this functionality indirectly, e.g., via Spring Framework's TransactionTemplate.

  1. If a transaction is not terminated by either committing or rolling back then Jakarta Transactions implementation automatically rolls it back.

    This setting is not to be confused with e.g. PostgreSQL idle_in_transaction_session_timeout

  2. "Subsequent"/"right before" is defined according to the program order 2

  3. I am talking about a race condition here.