jdbcspring-bootconnection-poolingjdbctemplatetomcat-jdbc

tomcat-jdbc pool datasource not reconnecting


I have a spring boot application with the following data source setup:

application.properties:

tomcat.jdbc.pool.url=jdbc:mysql://url/db
tomcat.jdbc.pool.username=username
tomcat.jdbc.pool.password=password
tomcat.jdbc.pool.initial-size=10
tomcat.jdbc.pool.test-on-borrow=true
tomcat.jdbc.pool.test-while-idle=true
tomcat.jdbc.pool.validation-query=SELECT 1
tomcat.jdbc.pool.driver-class-name=com.mysql.jdbc.Driver
tomcat.jdbc.pool.max_size=30
tomcat.jdbc.pool.min_size=7

DataSourceConfiguration.java

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;


@Configuration
public class DataSourceConfiguration {

    @Value("${tomcat.jdbc.pool.max_size}")
    private int maxSize;

    @Value("${tomcat.jdbc.pool.min_size}")
    private int minSize;

    @Value("${tomcat.jdbc.pool.initial-size}")
    private int initialSize;

    @Value("${tomcat.jdbc.pool.test-on-borrow}")
    private boolean testOnBorrow;

    @Value("${tomcat.jdbc.pool.test-while-idle}")
    private boolean testWhileIdle;

    @Value("${tomcat.jdbc.pool.username}")
    private String username;

    @Value("${tomcat.jdbc.pool.password}")
    private String password;

    @Value("${tomcat.jdbc.pool.url}")
    private String url;

    @Value("${tomcat.jdbc.pool.driver-class-name}")
    private String driverClassName;

    @Value("${tomcat.jdbc.pool.validation-query}")
    private String validationQuery;

    @Bean
    @Primary
    public DataSource dataSource() {
        DataSource dataSource = new DataSource();
        dataSource.setUrl(url);
        dataSource.setPassword(password);
        dataSource.setUsername(username);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setValidationQuery(validationQuery);
        dataSource.setInitialSize(initialSize);
        dataSource.setMaxIdle(maxSize);
        dataSource.setMinIdle(minSize);
        dataSource.setTestOnBorrow(testOnBorrow);
        dataSource.setTestWhileIdle(testWhileIdle);
        return dataSource;
    }
}

And finally I have a repository that utilizes this datasource in a jdbcTemplate:

@Repository
public class PositionRepository {

    private static JdbcTemplate jdbcTemplate;

    public PositionRepository() {}

    @Autowired
    public void setDataSource(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    ...
    ...
}

I confirmed that the datasource being passed to the JdbcTemplate constructor is indeed org.apache.tomcat.jdbc.pool.DataSource.

Every now and then, however, I get the following exception:

[2015-09-29 10:44:40.098] boot - 14124  INFO [http-nio-8888-exec-5] --- XmlBeanDefinitionReader: Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
[2015-09-29 10:44:40.302] boot - 14124  INFO [http-nio-8888-exec-5] --- SQLErrorCodesFactory: SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana]
[2015-09-29 10:44:40.308] boot - 14124  WARN [http-nio-8888-exec-5] --- SQLErrorCodesFactory: Error while extracting database product name - falling back to empty error codes
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
    at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:305) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:329) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:214) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.java:134) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.java:97) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.java:99) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:416) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:471) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:481) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.queryForList(JdbcTemplate.java:521) [spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.myproj.somename.repositories.PositionRepository.runQueryForList(PositionRepository.java:34) [classes/:?]
    at org.myproj.somename.repositories.PositionRepository.positionFindPaged(PositionRepository.java:52) [classes/:?]
    at org.myproj.somename.repositories.PositionRepository$$FastClassBySpringCGLIB$$ce8ed984.invoke(<generated>) [spring-core-4.1.7.RELEASE.jar:?]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) [spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) [spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) [spring-tx-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) [spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.myproj.somename.repositories.PositionRepository$$EnhancerBySpringCGLIB$$a986c62b.positionFindPaged(<generated>) [spring-core-4.1.7.RELEASE.jar:?]
    at org.myproj.somename.controllers.api.Positions.runPositions(Positions.java:148) [classes/:?]
    at org.myproj.somename.controllers.api.Positions.runPositions(Positions.java:93) [classes/:?]
    at org.myproj.somename.controllers.api.Positions.getPositions(Positions.java:61) [classes/:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[?:1.8.0]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) [spring-webmvc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [tomcat-

embed-core-8.0.23.jar:8.0.23]
        at ....
.....
.....
.....
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.23.jar:8.0.23]
        at java.lang.Thread.run(Thread.java:744) [?:1.8.0]
    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:1.8.0]
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:1.8.0]
        at java.lang.reflect.Constructor.newInstance(Constructor.java:408) ~[?:1.8.0]
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.Util.getInstance(Util.java:372) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:958) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.throwConnectionClosedException(ConnectionImpl.java:1236) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:1231) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.getMetaData(ConnectionImpl.java:2938) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.getMetaData(ConnectionImpl.java:2933) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0]
        at java.lang.reflect.Method.invoke(Method.java:483) ~[?:1.8.0]
        at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126) ~[tomcat-jdbc-8.0.23.jar:?]
        at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.0.23.jar:?]
        at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81) ~[tomcat-jdbc-8.0.23.jar:?]
        at com.sun.proxy.$Proxy83.getMetaData(Unknown Source) ~[?:?]
        at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:294) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        ... 103 more
    Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

    The last packet successfully received from the server was 16,234 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:1.8.0]
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:1.8.0]
        at java.lang.reflect.Constructor.newInstance(Constructor.java:408) ~[?:1.8.0]
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1038) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3422) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3322) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3762) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2531) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2489) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1446) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:455) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:405) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        ... 97 more
    Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
        at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2914) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3332) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3322) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3762) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2531) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2489) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1446) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:455) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:405) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        ... 97 more
    [2015-09-29 10:44:40.344] boot - 14124 ERROR [http-nio-8888-exec-5] --- [dispatcherServlet]: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.RecoverableDataAccessException: StatementCallback; SQL [SELECT * FROM ( SELECT ticker, `type`, strike, expiration, SUM(premium) / COUNT(*) avg_premium, SUM(newquantity)*multiplier `position` FROM ( SELECT IF (ACTION = 'BOUGHT', quantity, -quantity) newquantity, e.ticker_eurex ticker, e.multiplier, tr.*  FROM trade_record tr JOIN equity e ON tr.equity_id = e.id)  a WHERE  (  `expiration` >= '2015-09-29'  ) and  true  and trade_date <= '2015-07-09'  GROUP BY ticker, TYPE, strike, expiration ORDER BY  expiration desc , strike asc , position desc  LIMIT 0,100 ) z  WHERE  true  AND position <> 0 ]; Communications link failure

    The last packet successfully received from the server was 16,234 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.; nested exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

    The last packet successfully received from the server was 16,234 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.] with root cause
    java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
        at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2914) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3332) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3322) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3762) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2531) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2489) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1446) ~[mysql-connector-java-5.1.35.jar:5.1.35]
        at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:455) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:405) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:471) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:481) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.jdbc.core.JdbcTemplate.queryForList(JdbcTemplate.java:521) ~[spring-jdbc-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.myproj.somename.repositories.PositionRepository.runQueryForList(PositionRepository.java:34) ~[classes/:?]
        at org.myproj.somename.repositories.PositionRepository.positionFindPaged(PositionRepository.java:52) ~[classes/:?]
        at org.myproj.somename.repositories.PositionRepository$$FastClassBySpringCGLIB$$ce8ed984.invoke(<generated>) ~[spring-core-4.1.7.RELEASE.jar:?]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.myproj.somename.repositories.PositionRepository$$EnhancerBySpringCGLIB$$a986c62b.positionFindPaged(<generated>) ~[spring-core-4.1.7.RELEASE.jar:?]
        at org.myproj.somename.controllers.api.Positions.runPositions(Positions.java:148) ~[classes/:?]
        at org.myproj.somename.controllers.api.Positions.runPositions(Positions.java:93) ~[classes/:?]
        at org.myproj.somename.controllers.api.Positions.getPositions(Positions.java:61) ~[classes/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0]
        at java.lang.reflect.Method.invoke(Method.java:483) ~[?:1.8.0]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    .....
    .....
    ....


    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0]
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0]
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.23.jar:8.0.23]
                at java.lang.Thread.run(Thread.java:744) [?:1.8.0]

Could someone tell me what am I doing wrong. Isn't the whole point of using connection pooling to avoid this type of issues? Can I somehow tell tomcat-jdbc that I don't want exceptions unless it tried to reconnect X number of times? On top of that setTestOnBorrow and setTestOnIdle are both set to true.

Anyone has any ideas what's going on? Am I doing something wrong in my setup?

Cheers and thanks in advance!

P.S.

I truncated the exception at one point in order to fit within the max char limit of SO.


Solution

  • So long story short, I eventually ended up ditching jdbc-pool because it turned out to be an absolute waste of time. I decided to give HikariCP a shot with my Spring Boot backend and I couldn't be happier. It started handling the disconnection issues automatically and gracefully after a super basic setup.

    If you're running Spring Boot all you need is to add this to your pom.xml

    <!-- HikariCP DB Connection Pooling -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>2.4.1</version>
    </dependency>
    

    and then you just need to set the HikariCP properties accordingly. This is my setup and I had 0 problems with it

    # hikariCP
    spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
    spring.datasource.url=jdbc:mysql://localhost/some_db_name?useUnicode=true&characterEncoding=utf8&dumpQueriesOnException=true
    spring.datasource.username=<your_username_here>
    spring.datasource.password=<your_password_here>
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.pool-name=SpringBootHikariCP
    spring.datasource.maximum-pool-size=8
    spring.datasource.minimum-idle=5
    spring.datasource.max-lifetime=2000000
    spring.datasource.connection-timeout=30000
    spring.datasource.idle-timeout=30000
    spring.datasource.pool-prepared-statements=true
    spring.datasource.max-open-prepared-statements=250
    spring.datasource.validation-query=SELECT 1
    spring.datasource.pool-prepared-statements=true
    spring.datasource.pool-prepared-statements-cache-size=250
    spring.datasource.pool-prepared-statements-cache-sql-limit=2048
    spring.datasource.user-server-prepared-statements=true
    

    And finally this was the corresponding DataSource configuration using the properties above

    @EnableTransactionManagement
    @Configuration
    public class DataSourceConfiguration {
    
        // HikariCP
    
        @Value("${spring.datasource.username}")
        private String username;
    
        @Value("${spring.datasource.password}")
        private String password;
    
        @Value("${spring.datasource.url}")
        private String url;
    
        @Value("${spring.datasource.driver-class-name}")
        private String driverClassName;
    
        @Value("${spring.datasource.pool-name}")
        private String poolName;
    
        @Value("${spring.datasource.connection-timeout}")
        private int connectionTimeout;
    
        @Value("${spring.datasource.max-lifetime}")
        private int maxLifetime;
    
        @Value("${spring.datasource.maximum-pool-size}")
        private int maximumPoolSize;
    
        @Value("${spring.datasource.minimum-idle}")
        private int minimumIdle;
    
        @Value("${spring.datasource.idle-timeout}")
        private int idleTimeout;
    
        @Value("${spring.datasource.validation-query}")
        private String validationQuery;
    
        @Value("${spring.datasource.pool-prepared-statements}")
        private String cachePrepStmts;
    
        @Value("${spring.datasource.pool-prepared-statements-cache-size}")
        private String prepStmtCacheSize;
    
        @Value("${spring.datasource.pool-prepared-statements-cache-sql-limit}")
        private String prepStmtCacheSqlLimit;
    
        @Value("${spring.datasource.user-server-prepared-statements}")
        private String useServerPrepStmts;
    
        @Bean
        public DataSource primaryDataSource() {
    
            HikariConfig hikariConfig = new HikariConfig();
            hikariConfig.setDriverClassName(driverClassName);
            hikariConfig.setJdbcUrl(url); 
            hikariConfig.setUsername(username);
            hikariConfig.setPassword(password);
            hikariConfig.setMaximumPoolSize(maximumPoolSize);
            hikariConfig.setMinimumIdle(minimumIdle);
            hikariConfig.setConnectionTimeout(connectionTimeout);
            hikariConfig.setIdleTimeout(idleTimeout);
            hikariConfig.setConnectionTestQuery(validationQuery);
            hikariConfig.setPoolName("springHikariCP");
    
            hikariConfig.addDataSourceProperty("dataSource.cachePrepStmts", cachePrepStmts);
            hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSize", prepStmtCacheSize);
            hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSqlLimit", prepStmtCacheSqlLimit);
            hikariConfig.addDataSourceProperty("dataSource.useServerPrepStmts", useServerPrepStmts);
    
            HikariDataSource ds = new HikariDataSource(hikariConfig);
            return ds;
        }
    
    }
    

    That's what resolved the problem for me.