新框架的简单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();
就是测试连接是否可用的的选项。
暂时先这样了。目前这个简单的数据源还有不少问题需要处理。有空的时候还需要多琢磨琢磨。