记录一次压测,蛋疼的close statement error问题


前言

    最近甲方正在做压力测试,各种问题,不过有个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版本,这个问题不知道是不是这样子解决的,但是继续压测了几次,确实没有出现过。如果有知道原因的大佬,希望可以告知一下,感谢~~

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
这个错误通常是由于关闭数据库连接时出现问题引起的。可能的原因包括: 1. 未正确关闭 Statement 对象。在使用完 Statement 后,应该调用它的 `close()` 方法来释放资源。确保在 finally 块中关闭 Statement 对象,以保证无论代码是否出现异常都能正确关闭。 2. 在关闭 Statement 之前,尝试关闭了连接。应该先关闭 Statement,再关闭连接。如果尝试在关闭 Statement 后关闭连接,可能会引发此错误。 3. Statement 对象已经被关闭,但仍然在尝试使用它。请确保在使用 Statement 对象之前,检查它是否处于打开状态。 4. 数据库连接已经被关闭,但仍然在尝试使用它。请确保在使用数据库连接之前,检查连接是否处于打开状态。 5. 其他异常情况导致关闭 Statement 出现错误。这可能是由于数据库连接池配置不正确、数据库服务器故障等原因引起的。 要解决这个问题,可以按照以下步骤进行排查: 1. 确保在使用完 Statement 后正确关闭它,可以使用 try-with-resources 语句来自动关闭资源。 2. 检查关闭连接的顺序,确保先关闭 Statement,再关闭连接。 3. 检查代码中是否存在重复关闭 Statement 或连接的情况。 4. 检查数据库连接池的配置是否正确,是否存在连接超时或连接池满的情况。 如果问题仍然存在,可以查看具体的异常堆栈信息以及相关代码,以便更好地定位和解决问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穷儒公羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值