SpringManagedTransaction is not able to reconnect when connection is closed
jquesada-CLGX opened this issue · comments
We have a defined mapper calling an oracle stored procedure, the connections are managed by Hikari pool library. In some cases we have network issues making the DB not accessible for some time. After that the network is back but when trying to call the stored procedure the connection is always closed, SpringManagedTransaction is never trying to reconnect, making mandatory to restart the application to get this method available.
We have the following dependencies:
- com.zaxxer:HikariCP:4.0.3
- org.mybatis:mybatis:3.5.9
- org.mybatis:mybatis-spring:2.0.7
- com.oracle.database.jdbc:ojdbc8:21.5.0.0
Defining the following simplified mapper:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dummy.Mapper">
<select id="getInfo" parameterType="com.dummy.Params" statementType="CALLABLE" timeout="300" flushCache="true">
{CALL domain1.package1.getinfo(
#{referenceId1, mode=IN, jdbcType=VARCHAR})}
</select>
</mapper>
Datasource and session configuration
aaa:
datasource:
name: db
poolName: db
url: jdbc:oracle:thin:@//host:1525/DB
username: xxx
password: xxx
keepaliveTime: 180000
maxLifetime: 185000
minimumIdle: 1
maximumPoolSize: 2
hikari:
driver-class-name: oracle.jdbc.driver.OracleDriver
@Bean(name = "dataSource")
@ConfigurationProperties("aaa.datasource")
public HikariDataSource dataSource() {
HikariDataSource ds = avmLogDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
return ds;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactory() {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
Resource[] resourceArgs = new Resource[1];
ResourceLoader resourceLoader = new DefaultResourceLoader();
resourceArgs[0] = resourceLoader.getResource("classpath:com/dummy/Mapper.xml");
sqlSessionFactoryFraud.setMapperLocations(resourceArgs);
sqlSessionFactoryFraud.setTypeHandlers(new TypeHandler[]{new CalendarTypeHandler()});
sqlSessionFactoryFraud.setDataSource(dataSource);
return sqlSessionFactory;
}
When the connection is available in org.mybatis.spring.transaction.SpringManagedTransaction getConnection method we can see that the connection class type is (wrapping a ojdc connection object):
HikariProxyConnection@1231378000 wrapping oracle.jdbc.driver.T4CConnection@1f5b0c71
When the network is lost the DB connection type is:
HikariProxyConnection@1231378000 wrapping com.zaxxer.hikari.pool.ProxyConnection.ClosedConnection
After restablish the network connection the DB connection still the same
HikariProxyConnection@1231378000 wrapping com.zaxxer.hikari.pool.ProxyConnection.ClosedConnection
In this line the connection is never more null but it is closed and the code never tries to reconnect https://github.com/mybatis/spring/blob/master/src/main/java/org/mybatis/spring/transaction/SpringManagedTransaction.java#L66
This could be fixed easily checking if the connection is closed at that point:
public Connection getConnection() throws SQLException {
if (this.connection == null || this.connection.isClosed()) {
openConnection();
}
return this.connection;
}
Or another suggestion to solve this?
Hello @jquesada-CLGX ,
I don't understand the problem, but re-opening connection inside SpringManagedTransaction
may not be the right solution.
If it's a new connection, it's not the same transaction anymore, you know.
In general, if a connection is closed unexpectedly, there should be an exception.
You might have to set proper timeout depending on the situation, though (e.g. network timeout).
Close because no reply at long time. Of course you can reopen at any time. And probably, if calling the openConnection
again, this behavior cannot be resolved because the real connection managed by Spring Transaction (DataSourceUtils#getConnection
method return same connection instance during perform transaction).
Or another suggestion to solve this?
If you need retry, please consider to retry the transactional processing on other transaction. For example, you can use the Spring Retry feature.
SpringManagedTransaction is never trying to reconnect, making mandatory to restart the application to get this method available.
Really?? A SpringManagedTransaction
instance create at beginning new transaction. Therefore, I cannot believe this behavior. If you reopen this issue, please provide a repro project. Thanks.