Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException:

近期工作中遇到一个问题:数据库连接超时异常。项目架构是SSM+Boot。近期每天早上都有管理员反映后管登不上去了,并发来了截图
在这里插入图片描述

异常信息

### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 20, maxActive 20, creating 0
### The error may exist in URL [jar:file:/mall/jar/mall-admin-2.0-SNAPSHOT.jar!/BOOT-INF/lib/mall-mbg-1.0-SNAPSHOT.jar!/com/macro/mall/mapper/UmsAdminMapper.xml]
### The error may involve com.macro.mall.mapper.UmsAdminMapper.selectByExample
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 600, maxActive 600, creating 0
        at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)

报错信息为在执行UmsAdminMapper下的selectByExample方法时连接超时。我仔细检查了SQL,确认无误,排除了SQL问题,然后去检查连接配置,都正常呀,连接数也没有超。于是便开始了面向百度,Google开发,搜了很多解决办法都不行。

问题分析

druid既然已经报错active 600, maxActive 600,肯定就是当前druid确实还有600个未释放的链接资源,但是通过show processlist查看实际连接确实没有600个,于是得出结论:有通过druid获取了连接,但是还未释放连接。未释放的连接在超过一定时间后,被mysql主动释放,所以服务实际存活的连接确实不足600个,但是mysql释放连接之后不会告诉druid,所以druid认为还是600个连接正在使用。

突然想到近期的一个新需要,需要从第三方调接口拉取第三方的商品,进行入库。因为数据量有点大,便直接采用了mybatis的批处理方式,创建sqlSession,指定BATCH模式。代码:

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
ProductMapper mapper = session.getMapper(ProductMapper.class);
for (int i = 0; i < list.size(); i++) {
    mapper.insertSelective(list.get(i));
    //每1000条提交一次防止内存溢出
    if (i % 1000 == 999) {
        session.commit();
        session.clearCache();
    }
}
session.commit();
session.clearCache();

大家第一眼看去是不是没毛病呀,我写的时候也觉得没毛病,测试功能也正常,但是当我仔细看了一眼代码,发现个致命的错误。没有关闭连接。手动关闭连接这个操作已经很久没有用过了。每逢遇到需要释放资源的都使用 try-with-resources ,结果这次忘了这茬了。

所以这块代码每运行一次就会开启一个资源,然后没有释放,累计下来便达到了600。加上 try-with-resources之后,成功解决。

try-with-resources

java1.7 引入了 try-with-resources 声明,将 try-catch-finally 简化为 try-catch,这其实是一种语法糖,在编译时会进行转化为 try-catch-finally 语句。它要求在 try-with-resources 声明中定义的变量实现了 AutoCloseable 接口或者Closeable接口(Closeable是AutoCloseable 的子类),这样在系统可以自动调用它们的close方法,从而替代了finally中关闭资源的功能。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

慕辰Sir

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

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

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

打赏作者

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

抵扣说明:

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

余额充值