java.sql.SQLException: connection holder is null;

一、问题来源分析

出现的错误 :

Cause: java.sql.SQLException: connection holder is null; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; connection holder is null; nested exception is java.sql.SQLException: connection holder is null

1.出现的原因,数据库链接丢失,出现的原因是这样的,我需要执行定时任务去定时更新数据库的数据,每次分页循环跟新,开始数据不多,能成功,后来数据量大了,到了下一次任务开始也不能结束,但是数据库已经报错了,报错理解起来也很简单,数据连接丢失,一开始问了度娘,修改了一下的参数

<!-- 1800秒,也就是30分钟 修改为了36000,即10小时-->     
<property name="removeAbandonedTimeout" value="36000" />

以为问题解决了,到但是过几天还是报错了,仔细想了下,业务代码得改啊,不然的话,连接肯定会超时的,于是修改了业务代码,采用了多线程,每次获取数据库的少于设置的removeAbandonedTimeout的时间即可以成功,功能算是可以了;

二、问题的思考

近段时间学习了mysql,对这个问题冲新思考了下

  1. 首先来说下数据的长连接和短连接:

    短连接:短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个;

    长连接:长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接;

    建立连接的过程是比较复杂的,也就有了数据库连接池的出现,但是,我理解为每次从连接池中获取到一个数据库连接,然后不停的执行业务代码,也相当于一个长连接;我的问题就应该是这样出现的。

  2. 如果除开数据源,是建议多使用长连接的,可以减少建立数据库链接的开销的,但是全部使用长连接后,你可能会发现,有些时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。

  3. 后面去看定时任务日志的时候,定时任务每次没执行完成,就报错了;客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时,及就算采用了数据库链接池,链接的时间过长,也会被数据库断开;

三、 问题拓展优化

上面我所说的业务的关联性不是很大,如果业务要求有前后的关联关系,而且时间又比较长,该怎么半呢?

  • 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连

  • 如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

    第一个方案比较好理解,第二个方案就很只能针对高版本的mysql了,不过这样就比较好解决上面出现的问题了;

posted @ 2019-12-09 14:36  李维维(levi)  阅读(6952)  评论(0编辑  收藏  举报