问题描述

在使用activiti做工作流的过程中,偶尔出现有长时间运行的任务出现数据库异常,主要片段如下:




  • Could not retrieve transation read-only status server
  • The last packet successfully received from the server was 4,555,119 milliseconds ago.
  • Caused by: java.net.SocketException: Connection reset

排查&解决

跟踪到数据库驱动里面查看发现这段代码:


大意是通过语句select @@session.tx_read_only来探测连接是否只读,然后发生了异常,异常的原因是距离上一个包接收的时间太长了,连接被重置了;
到这里的话基本上可以确定是服务器将长时间未使用的连接给回收掉了,服务器经过多长时间回收是由配置项wait_timeout来设置的, 可以通过show global variables like 'wait_timeout'来查看,单位是s;然后我们服务器配置的时间是3600s, 一个小时,所以有两个办法去解决问题:

  • 每隔一段时间去访问一次数据库,主动保持连接是活的
  • 延长wait_timeout

最终是通过延长wait_timeout来解决的,但是不是调整服务器的全局配置,而是在连接参数里面设置session的wait_timeout参数,例如jdbc:mysql://localhost:3306/db?sessionVariables=wait_timeout=10800

插曲

一开始我想通过第一种方法解决, 我觉得驱动参数是可以有对应的配置的(结果证明是没有的), 让我产生误解的参数有几个(dbcp连接池):

  • testWhileIdle [true/false]:对空闲连接进行测试,如果失败,直接从线程池中移除
  • validationQuery:进行以上测试的sql语句
  • timeBetweenEvictionRunsMillis:每隔多久运行一次清理线程
  • minEvictableIdleTimeMillis:发现空闲线程后最小多长时间回收

以上参数都是针对连接池中未分配的连接而定的, 对于已分配的连接是无效的,我纯粹是被它们的名称给欺骗了:((