-
Notifications
You must be signed in to change notification settings - Fork 50
Description
Describe the bug
I have a Spring Boot application with HikariCP and hibernate running with autocommit=false like this (for this reason):
spring:
hikari:
auto-commit: false
jpa:
properties:
hibernate.connection.provider_disables_autocommit: trueDuring a recent event of applying an OS patch on my aurora cluster, the event lead to some connection being completely broken in the pool. These connections were always throwing the error with the code 08007 which are flagged as DO_NOT_EVICT by our SQLExceptionOverride, as suggested in the driver readme. This meant that all requests using that connection would end up as a 500.
Following this, I've circled back to the documention to see that the proper usage of this connection reuse behavior is to reset the session state ourselves in the code. However, this is easily overlooked IMO and it seems to lead to a completely broken connection in my case.
Expected Behavior
We should never have a connection not being evicted that is not in a valid state.
Current Behavior
Session state is completely lost and we end up with a broken connection in the pool.
Here is the stack trace I was getting (I've removed some irrelevant frames) :
org.springframework.orm.jpa.JpaSystemException: Unable to commit against JDBC Connection; nested exception is org.hibernate.TransactionException: Unable to commit against JDBC Connection
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:331)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)
at com.coveo.cloud.baseservice.configuration.datasource.GlobalClusterAwareTransactionManager.commit(GlobalClusterAwareTransactionManager.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.hibernate.TransactionException: Unable to commit against JDBC Connection
at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.commit(AbstractLogicalConnectionImplementor.java:92)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:282)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)
... 203 common frames omitted
Caused by: java.sql.SQLException: Can't call commit when autocommit=true
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:67)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ConnectionImpl.commit(ConnectionImpl.java:801)
at jdk.internal.reflect.GeneratedMethodAccessor140.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.ConnectionProxy.lambda$invoke$0(ConnectionProxy.java:198)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.plugins.DefaultConnectionPlugin.execute(DefaultConnectionPlugin.java:80)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.plugins.NodeMonitoringConnectionPlugin.execute(NodeMonitoringConnectionPlugin.java:249)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.plugins.failover.FailoverConnectionPlugin.execute(FailoverConnectionPlugin.java:276)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.plugins.ConnectionPluginManager.execute(ConnectionPluginManager.java:138)
at software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.ConnectionProxy.invoke(ConnectionProxy.java:195)
at jdk.proxy3/jdk.proxy3.$Proxy178.commit(Unknown Source)
at com.zaxxer.hikari.pool.ProxyConnection.commit(ProxyConnection.java:387)
at com.zaxxer.hikari.pool.HikariProxyConnection.commit(HikariProxyConnection.java)
at com.coveo.cloud.baseservice.configuration.datasource.readonly.ReadOnlyConnection.commit(ReadOnlyConnection.java:78)
at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.commit(AbstractLogicalConnectionImplementor.java:86)
... 206 common frames omitted
Reproduction Steps
Have a autocommit=false setup and trigger a non graceful failover (a failover with a good period of unavailability, not the button in the rds console).
Possible Solution
- Would it be possible to keep the connection session parameters in a variable somewhere and restore it when the failover kicks in?
- The documentation should be updated with an emphasis that you need to handle the autoCommit status of the connection in the case of a failover.
- Do you have any experience with hooks or library that could do the retry logic mentioned in the readme when using hibernate + spring for tx management?
Additional Information/Context
No response
The AWS JDBC Driver for MySQL version used
1.1.7
JDK version used
OpenJDK 64-Bit Server VM Zulu17.42+19-CA (build 17.0.7+7-LTS, mixed mode)
Operating System and version
azul jdk container running on ubuntu 20.04