-
Notifications
You must be signed in to change notification settings - Fork 38.4k
Suppress "Unable to rollback against JDBC Connection" in case of timeout (connection closed) #34714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
What was the application exception that got overridden, actually, in that error log entry? Did that one indicate a timeout? I suppose the Oracle driver automatically cancels the current statement in case of a timeout, but I'm not sure why it automatically closes the connection then. In terms of exception content, we are ultimately exposing what the JDBC driver and the connection pool give us, to some degree through Hibernate which actually handles the transaction. If there is no timeout indicated there, it won't be obvious from the exception content. |
In logs I see multiple errors and stacktraces but the first one is this one:
Then I see this error:
And then I have this error:
So there is a SQLTimeoutException and then a QueryTimeoutException but this is not what I receive at the end when I catch Exception. |
So we correctly identify it as a In terms of the actual exception thrown indicating the rollback failure, that's rather unfortunate but part of the transaction logic there: Generally speaking, rollback failures are a harder problem than a statement-level exception that happened before, and the harder problem overrides. Now that is a purely technical judgement - for a query timeout with auto-closing of the connection, we could try to provide a better user experience indeed. It's not entirely clear how we can technically reason about that scenaro in the transaction interceptor, though. It's still not clear why the connection gets automatically closed before we have a chance to formally trigger a rollback. Since you are using a rather long 40-second timeout at the transaction level, you could double-check whether Hikari happens to interfere with a timeout of its own there. As far as I can see, Hikari uses a connection wait timeout of 30 seconds - although that does not seem to immediately apply here, you could try to lower your transaction-level timeout to 25 seconds, for example (below Hikari's 30 seconds), and see whether the rollback works then. |
At least if we can keep the root cause and have a "Caused by" with the original exception (
I will try it on Monday at work and I will keep you informed. Thank you. |
Admittedly, that rollback failure is a misleading exception, even more so since this is about a read-only transaction. The rollback follows from the technical demarcation that implies a transaction-scoped Connection underneath, where the transaction scope formally needs to end on the Connection before returning it to the pool (even if no actual transactional operations happened in this particular scope). Such a transaction demarcation is generally recommended for read operations as well. For JPA, it forces the EntityManager to use the same Connection for all operations (whereas it could otherwise obtain a fresh Connection per operation), and you could possibly enforce reading with a consistent isolation level across multiple entities and queries. Last but not least, it allows the connection pool to be declared with an Alternatively, you could declare That said, we should try to sort out the behavior for your original scenario as well. A rollback failure just due to the Connection having been prematurely closed is arguably pointless, given that the transaction manager intends to close the Connection right after the rollback anyway. What complicates this is that it is actually Hibernate performing the rollback, so we can't easily check the Connection status ourselves. |
Assuming that your scenario lets the underlying connection expire and we then fail in the transaction cleanup step where the connection is expected to be active still: There is not much we can do about a closed connection with a Hibernate-managed rollback. We cannot intercept the rollback for a Connection check, and the rollback exception does not cleanly indicate that the connection was closed since the cause is a plain That said, we are able to cover this with Spring's For reference: https://vladmihalcea.com/lazyconnectiondatasourceproxy-spring-data-jpa/ - setting that up right now is beneficial in other ways but won't address your immediate scenario with a late transaction timeout yet. I've added lenient rollback handling there for 6.2.6 now. Please give such a |
Hi,
I use Spring Boot 3.4.4 with an Oracle database (JpaTransactionManager, JpaRepository and Hikari connection are used).
I set a timeout on @transactional to stop the treatment of the service if it is too long (due to long database queries according to parameters) like this:
@Transactional(readOnly = true, timeout = 40)
If the timeout is reached for the transaction, then I expect to have an exception related to this reason thrown by JPA transaction manager (ex: JPATimeoutException) but I have the following exception with no link to the timeout:
If I check logs, I see that a cancel of the query has been asked (because of the timeout if I understand):
ORA-01013: user requested cancel of current operation
Then, I see a log indicating that the transaction is converted into a rollback exception:
ERROR o.s.t.i.TransactionInterceptor - Application exception overridden by rollback exception
Also, it seems that the connection is closed after the cancel.
The rollback exception provokes a rollback in HikariProxyConnection that cannot be done because the connection has been closed.
If I catch the exception thrown by the service (on which I have @transactional with timeout), I have the JpaSystemException with a root cause indicating that that the connection is closed (see the stacktrace above). The information about the timeout reached is lost and I am not able to identify that I had a timeout (as a "Caused by" at least).
Is it possible to keep at least the root cause (=the timeout was reached) because here it is strange to have nothing related to it?
The text was updated successfully, but these errors were encountered: