com.mysql.cj.exceptions.ConnectionIsClosedException: No operations allowed after connection closed.

Posted Hi,all

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了com.mysql.cj.exceptions.ConnectionIsClosedException: No operations allowed after connection closed.相关的知识,希望对你有一定的参考价值。

目录

一、功能背景

二、错误信息

三、相关代码

四、问题原因

四、解决办法

1、修改dbDriver

2、修改数据库配置

3、通过修改配置文件信息


一、功能背景

在SpringBoot项目中使用第三方数据库进行业务处理,需手动配置连接信息,手段创建连接进行操作第三方数据库。

二、错误信息

Caused by: com.mysql.cj.exceptions.ConnectionIsClosedException: No operations allowed after connection closed.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
	at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
	at com.mysql.cj.NativeSession.checkClosed(NativeSession.java:1171)
	at com.mysql.cj.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:573)
	at com.mysql.cj.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:1595)
	... 96 common frames omitted

三、相关代码

public List<Map<String, Object>> getDetailData() throws Exception 
        String jdbcUrl = "jdbc:mysql://xxxxxxx:3306/demo";
        String driverName = "com.mysql.cj.jdbc.Driver";
        String username = "";
        String password = "";
        DBHelper dbHelper = new DBHelper(jdbcUrl, driverName, username, Base64.decodeStr(password));
        Connection connection = dbHelper.conn;
        if (ObjectUtil.isEmpty(connection)) 
            throw new Exception("数据库连接异常");
        
        String variablesSql = "show variables like 'lower_case_table_names'";
        // 预执行加载
        PreparedStatement pst = null;
        // 结果集
        ResultSet resultSet = null;
        List<Map<String, Object>> list = new ArrayList<>();
        try 
            pst = connection.prepareStatement(variablesSql);
            resultSet = pst.executeQuery();
            ResultSetMetaData rsmd = resultSet.getMetaData();
            int columnCount = rsmd.getColumnCount();
            while (resultSet.next()) 
                Map<String, Object> valueMap = new LinkedHashMap();
                for (int i = 1; i <= columnCount; i++) 
                    // 通过序号获取列名,起始值为1
                    String columnName = rsmd.getColumnLabel(i);
                    // 通过列名获取值
                    String columnValue = resultSet.getString(columnName);
                    valueMap.put(columnName, columnValue);
                
                list.add(valueMap);
            
         catch (Exception e) 
            log.error("关闭数据库连接,出现异常", e);
            throw new Exception("获取表信息,出现异常", e);
         finally 
            try 
                if (Objects.nonNull(resultSet)) 
                    resultSet.close();
                
                if (Objects.nonNull(pst)) 
                    pst.close();
                
                if (Objects.nonNull(connection)) 
                    connection.close();
                
             catch (Exception e) 
                log.error("关闭数据库连接,出现异常", e);
            
        
        return list;
    

四、问题原因

Mysql服务器默认的“wait_timeout”是8小时,也就是说一个connection空闲超过8个小时,Mysql将自动断开该connection。这就是问题的所在,在C3P0 pools中的connections如果空闲超过8小时,Mysql将其断开,而C3P0并不知道该connection已经失效,如果这时有Client请求connection,C3P0将该失效的Connection提供给Client,将会造成上面的异常。

四、解决办法

1、修改dbDriver

把spring.datasource.driverClassName修改为:com.mysql.jdbc.Driver

修改后代码为:

public List<Map<String, Object>> getDetailData() throws Exception 
        String jdbcUrl = "jdbc:mysql://xxxxxxx:3306/demo";
        String driverName = "com.mysql.jdbc.Driver";
        String username = "";
        String password = "";
        DBHelper dbHelper = new DBHelper(jdbcUrl, driverName, username, Base64.decodeStr(password));
        Connection connection = dbHelper.conn;
        if (ObjectUtil.isEmpty(connection)) 
            throw new Exception("数据库连接异常");
        
        String variablesSql = "show variables like 'lower_case_table_names'";
        // 预执行加载
        PreparedStatement pst = null;
        // 结果集
        ResultSet resultSet = null;
        List<Map<String, Object>> list = new ArrayList<>();
        try 
            pst = connection.prepareStatement(variablesSql);
            resultSet = pst.executeQuery();
            ResultSetMetaData rsmd = resultSet.getMetaData();
            int columnCount = rsmd.getColumnCount();
            while (resultSet.next()) 
                Map<String, Object> valueMap = new LinkedHashMap();
                for (int i = 1; i <= columnCount; i++) 
                    // 通过序号获取列名,起始值为1
                    String columnName = rsmd.getColumnLabel(i);
                    // 通过列名获取值
                    String columnValue = resultSet.getString(columnName);
                    valueMap.put(columnName, columnValue);
                
                list.add(valueMap);
            
         catch (Exception e) 
            log.error("关闭数据库连接,出现异常", e);
            throw new Exception("获取表信息,出现异常", e);
         finally 
            try 
                if (Objects.nonNull(resultSet)) 
                    resultSet.close();
                
                if (Objects.nonNull(pst)) 
                    pst.close();
                
                if (Objects.nonNull(connection)) 
                    connection.close();
                
             catch (Exception e) 
                log.error("关闭数据库连接,出现异常", e);
            
        
        return list;
    

2、修改数据库配置

修改服务端连接超时时间

show global variables like 'wait_timeout';

set global wait_timeout=172800;

3、通过修改配置文件信息

#连接池配置
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validation-query=SELECT 1
spring.datasource.test-on-borrow=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800

   配置datasource时需要配置相应的连接池参数,定是去检查连接的有效性,定时清理无效的连接。配置完重启服务即生效。

  注:第三种方案不适用本文章对应的功能,只是一种解决方案。

以上是关于com.mysql.cj.exceptions.ConnectionIsClosedException: No operations allowed after connection closed.的主要内容,如果未能解决你的问题,请参考以下文章