生产上Tomcat出现 Connection has already been closed.问题,但是在uat测试是好的!
遇见两次:
1.某个程序dao中执行逻辑异常复杂,有时候需要执行一分多钟,uat正常执行,生产上个别执行时间长的会出现Connection has already been closed!
2.某程序在service中注入dao,业务逻辑中获取一批数据放在list中遍历,每遍历一次用dao直接调用方法,大概四五个dao的方法,过一会出现Connection has already been closed!
问题根本原因:
1.小伙伴配置时,会添加以下连接配置参数
removeAbandoned="true"
removeAbandonedTimeout="60"(removeAbandonedTimeout”(默认300秒))
logAbandoned="true"
有时候代码中会有从连接池中获取连接使用后忘记了连接的关闭,这样连池的连接就会逐渐达到maxActive直至连接池无法getConnection。
连接池一般提供检查功能,即设置了removeAbandoned="true",连接就可以自动回收。
连接自动回收判断标准:
<!--是否回收已经超过 removeAbandonedTimeout 设置的无效连接,自动回收超时连接 启动机制:getNumActive() > getMaxActive() - 3 和 getNumIdle() < 2 假设maxActive=20,而当前18个活动连接,1个空闲连接,机制将会启动 但是只有在活动连接没有使用的时长超过“removeAbandonedTimeout”(默认300秒)上述配置为60s,的连接将被回收-->
配置logAbandoned="true",会在回收连接时打印日志。removeAbandoned是连接池的高级功能,生产环境上应当慎重配置。
因为有时应用程序执行长事务,在这种情况下,极有可能连接会被连接池误回收。
该配置一般在uat使用,为了定位连接泄漏的位置而去使用。生产环境中连接的关闭应该靠程序自己保证。
问题一产生原因:如上述所说,直接对号入座
解决:1.适当增大 removeAbandonedTimeout时间,让单次获取的连接能够执行时间更长一点,让其支持更长一点的事务。
问题二产生原因:需要拐个弯,因为spring中配置事务时配置的service开启一个事务,在service中拿到连接开启一个事务,而遍历中一直使用注入的dao去调用方法,
其本质就是一直使用一个连接,不会遍历一次执行完重新获取连接,导致该连接超时被tomcat关闭回收。
解决2:将所有dao层方法抽出来另放一个业务service层,注入dao层,方法里使用dao的调用方法。在原来的service层中注入业务service,原有dao调用的方法,全部替换成业务service调用的方法。
这样每次业务service调用到(update、insert、delete)方法,就开启一个事务,执行完就回收。再执行就有获取一个连接,执行到事务方法后,又会主动关闭,
就不会因连接超时被tomcat强行回收了!