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.相关的知识,希望对你有一定的参考价值。
目录
一、功能背景
在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.的主要内容,如果未能解决你的问题,请参考以下文章