前言
最近甲方正在做压力测试,各种问题,不过有个druid连接池的close statement error问题一直都有
知道你们心急,直接把结果写在前边:最终换了1.2.1版本,再次压测了几次,后台日志确实没有出现close statement error报错信息了
一、问题的出现
甲方测试人员在做压测时(压测时出现,平时不会出现),后台日志频繁出现close statement error错误,数据库连接池用的是druid-1.1.10(重点)。而且问题出现后,虽然后台报错,但是不影响交易,报错如下:
二、尝试解决
既然有明显的错误,那就百度吧,面向百度编程。翻了一圈基本都是说添加:testidle,testonborrow、testonreturn 等参数,那就加吧,但是加上了。结果一压还是一样,那一刻心都凉了,心态崩了
还有说是因为把resultSet.close()、statement.close()、 connection.close()的关闭顺序写反了,导致这个问题,但是看了代码都是用是JdbcTemplate操作的。所以这个情况基本也可以排除了
三、一丝曙光
本来都快绝望了,但是架不住测试妹子一直追问,只能去git上找druid论坛看看了,直到看到以下回答:
顺着这个思路去翻一下druid代码(这边用的是1.2.1版本),如下:
可以看到他这边是忽略这个错误的,写个代码测试一下吧(这边因为服务器上是并不是中文,所以用US获取错误信息),如下:
package com.hqd;
import com.alibaba.druid.util.JdbcUtils;
import java.sql.*;
import java.util.Locale;
import java.util.ResourceBundle;
public class CloseStatementTest {
public static void main(String[] args) {
Statement stmt = new Statement() {
@Override
public ResultSet executeQuery(String sql) throws SQLException {
return null;
}
@Override
public int executeUpdate(String sql) throws SQLException {
return 0;
}
@Override
public void close() throws SQLException {
ResourceBundle bundle = ResourceBundle.getBundle("oracle.jdbc.driver.Messages", new Locale(""));
System.out.println(bundle.getString("ORA-17008"));
throw new SQLRecoverableException(bundle.getString("ORA-17008"));
}
@Override
public int getMaxFieldSize() throws SQLException {
return 0;
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
}
@Override
public int getMaxRows() throws SQLException {
return 0;
}
@Override
public void setMaxRows(int max) throws SQLException {
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
}
@Override
public int getQueryTimeout() throws SQLException {
return 0;
}
@Override
public void setQueryTimeout(int seconds) throws SQLException {
}
@Override
public void cancel() throws SQLException {
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public void setCursorName(String name) throws SQLException {
}
@Override
public boolean execute(String sql) throws SQLException {
return false;
}
@Override
public ResultSet getResultSet() throws SQLException {
return null;
}
@Override
public int getUpdateCount() throws SQLException {
return 0;
}
@Override
public boolean getMoreResults() throws SQLException {
return false;
}
@Override
public void setFetchDirection(int direction) throws SQLException {
}
@Override
public int getFetchDirection() throws SQLException {
return 0;
}
@Override
public void setFetchSize(int rows) throws SQLException {
}
@Override
public int getFetchSize() throws SQLException {
return 0;
}
@Override
public int getResultSetConcurrency() throws SQLException {
return 0;
}
@Override
public int getResultSetType() throws SQLException {
return 0;
}
@Override
public void addBatch(String sql) throws SQLException {
}
@Override
public void clearBatch() throws SQLException {
}
@Override
public int[] executeBatch() throws SQLException {
return new int[0];
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public boolean getMoreResults(int current) throws SQLException {
return false;
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
return null;
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return 0;
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
return false;
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return false;
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return false;
}
@Override
public int getResultSetHoldability() throws SQLException {
return 0;
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
}
@Override
public boolean isPoolable() throws SQLException {
return false;
}
@Override
public void closeOnCompletion() throws SQLException {
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return false;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
};
JdbcUtils.close(stmt);
}
}
发现确实没有报错信息了,如下:
四、最终解决
总算看到希望了,怀着激动地心情去试了一把,结果现实又给我了一次毒打。还是打印出来异常了。最后对了比较一下druid的版本,发现服务器上用的是1.1.10版本,再去翻一下代码,如下:
用上面的代码再次测试一下,如下:
这里可以看到,1.1.10版本是直接打印了。这边不要奇怪,为什么debug也会打印,因为被提升级别了
最终换了1.2.1版本,再次压测了几次,后台日志确实没有出现close statement error报错信息了
总结
最终是把druid从1.1.10版本换成1.2.1版本,这个问题不知道是不是这样子解决的,但是继续压测了几次,确实没有出现过。如果有知道原因的大佬,希望可以告知一下,感谢~~