问题描述:有一个定时任务,每隔一段时间往接口推送一批数据,将推送成功的数据状态码改成1,但是在部署运行一天后就没有收到数据了。看了下日志文件报错:
Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
第一时间想到的是数据库连接未释放,然后我就先去检查了配置文件,发现好像没什么问题,之前的接口也一直都是这样的配置
spring:
jpa:
open-in-view: false
于是我又把hikari连接池的默认配置修改了一下,在网上找的大部分教程都是教我们修改这个配置,但是我改了之后也没啥效果,唯一的效果就是我把最大连接数改大之后,开始是运行一天报错的,现在能运行三天了,然后一如既往的报错。
后面我去查看oracle的连接状态
select program,machine,count(*) from v$session group by machine,program order by 3 desc;
查到有一个连接有一千多条,这一看就不正常了。那问题大概率就是连接未释放,然后再查看一下具体的状况。
select PROGRAM,MACHINE,STATUS,LOGON_TIME,TIME_REMAINING_MICRO from v$session where PROGRAM='JDBC Thin Client' and MACHINE='epcfileserver01';
--这里的PROGRAM跟MACHINE是上一步查出来的那个值
字段解释:更多字段解释参考官方文档V$会话 (oracle.com)
PROGRAM:操作系统程序名
MACHINE:操作系统计算机名
STATUS:会议状态
ACTIVE- 当前正在执行 SQL 的会话
INACTIVE- 会话处于非活动状态,没有配置的限制或尚未超过配置的限制
KILLED- 标记为被杀死的会话
CACHED- 会话临时缓存以供 Oracle*XA 使用
SNIPED- 已超出某些配置限制(例如,为资源管理器使用者组指定的资源限制或在用户配置文件中指定的idle_time)的非活动会话。此类会话将不允许再次激活。
LOGON_TIME:登陆时间
TIME_REMAINING_MICRO:
> 0 当前等待的剩余时间量(以微秒为单位)
0 当前等待已超时
-1 会话可以在当前等待中无限期等待
NULL 会话当前未等待
那么是什么导致了这个问题呢,我想了下会不会是我设置定时任务的while循环里面出问题了,while循环里面我用的是new RestTemplate()去调用接口,然后我又去搜了一下它的一个销毁,结果发现这玩意好像是不会自己销毁的。所以可能是每一次while循环都会去新建一个连接未释放,最终导致报错。于是改了下代码,不再去new一个RestTemplate了而是去创建个bean。目前我改了之后暂时没报错再等几天试试。每个人的问题可能都不一样还是得细心去找
一周过去了,接口正常运行,没有报错了,只需要把bean对象放在容器里,然后执行完的时候把容器关掉,bean对象就会自动销毁,这样连接也就释放了。
@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
//RestTemplate restTemplate = new RestTemplate();不再去new一个对象
while (true){
//创建容器
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(RestTemplateConfiguration.class);
RestTemplate restTemplate = context.getBean(RestTemplate.class);
restTemplate.getForEntity(requestURL, String.class);
//关闭容器后bean自动销毁
context.close();
log.info("一次插入结束,线程休眠一小时");
Thread.sleep(3600000);
log.info("休眠结束,启动定时推送");
}