Nemo

Nemo 关注TA

路漫漫其修远兮,吾将上下而求索。

Nemo

Nemo

关注TA

路漫漫其修远兮,吾将上下而求索。

  •  普罗旺斯
  • 负责帅就完事了
  • 写了1,495,102字

该文章投稿至Nemo社区   Java  板块 复制链接


MySQLNonTransientConnectionException: No operations allowed after connection closed.

发布于 2018/01/26 19:10 5,148浏览 0回复 6,525

新框架的简单demo上线一晚上后,简单数据源出现了这么一个问题:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
        at com.mysql.jdbc.Util.getInstance(Util.java:408)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:918)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
        at com.mysql.jdbc.ConnectionImpl.throwConnectionClosedException(ConnectionImpl.java:1198)
        at com.mysql.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:1193)
        at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4046)
        at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4015)
        at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4022)
        at com.nemo.store.data.DataHelper.insert(DataHelper.java:83)
        at com.nemo.store.dao.SysLogDaoImpl.insert(SysLogDaoImpl.java:31)
        at com.nemo.store.service.SysLogServiceImpl.insert(SysLogServiceImpl.java:47)
        at com.nemo.store.filter.GlobalFilter.doFilter(GlobalFilter.java:37)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 30,770,436 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989)
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3559)
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3459)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3900)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2501)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
        at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2079)
        at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2013)
        at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5104)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1998)
        at com.nemo.store.data.DataHelper.insert(DataHelper.java:91)
        ... 20 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:3011)
        at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3469)
        ... 31 more

字面上看,大概是某个连接已经失效了。

先看下数据库配置:

show  global  variables like  'wait_timeout';

从结果上看,连接的有效时间为8小时。

之前上线的前一两个小时连接还是正常的,出现问题在一晚上后,大约也是8小时。
问题大概也就在这里了。

这样子看的话,有两种方案解决这个问题:

1、简单数据源在的连接在使用前,需要先测试时候有效,无效则取新的连接。

2、定时安排线程去激活可能许久没有使用的连接,让连接始终保持有效。

实现起来,必然是第一种实现会更简单一些,所以这里先使用第一个方案来解决这个问题:

/**
     * 得到一个数据库连接
     * @return
     * @throws SQLException
     */
    public Connection getConnection() throws SQLException {
        synchronized (pool) {
            if (pool.size() > 0) {
                //如果连接池中还有剩余连接,则取即可,否则需要新建连接
                Connection connection = pool.removeFirst();
                try {
                    connection.prepareStatement("SELECT 'X' ").executeQuery();
                }catch (Exception e){
                    connection = getConnection(username,password);
                }
                return connection;
            } else{
                Connection connection = getConnection(username,password);
                return connection;
            }
        }
    }

这里在从连接池中取得连接后,先测试下该连接是否可用,如果不可用,则从jdbc重新取得连接即可。

这里的

connection.prepareStatement("SELECT 'X' ").executeQuery();

就是测试连接是否可用的的选项。


暂时先这样了。目前这个简单的数据源还有不少问题需要处理。有空的时候还需要多琢磨琢磨。

点赞(0)
点了个评