今天解决了一个使用springmvc框架的项目上线后数据库连接慢慢被占满的bug,由于项目经手不同的开发人员进行开发,导致项目里出现了使用原生的jdbc连接去交互数据库,第一次查找问题定位到问题是获取数据库(connection)连接没有关闭,原本以为关闭连接就会解决问题,结果发版几天后数据库连接依然被占满,查看数据库连接发现全部是select 1和show transaction isolation level查询语句占满了连接。
仔细研究代码发现原生jdbc交互获取连接的使用:
ApplicationContext cxt = new ClassPathXmlApplicationContext("spring-servlet.xml");
DataSource ds = cxt.getBean("xxx", DataSource.class)
在我们刚开始学习jdbc阶段,课本或课程都是教我们使用上面的方法获取数据库连接,但这种获取方法会在每执行一次就会初始化一次spring-servlet.xml配置文件里的数据库c3p0连接池的配置(实际配置文件所有bean都会重新初始化),导致数据库连接每次都增长(初始化的c3p0连接池几次就增长几个连接,且该连接不会释放--->是c3p0需要保留的空闲连接)解决办法,把上面获取connection的方法改为获取spring容器中的c3p0数据库连接池的connection
DataSource ds = (DataSource) SpringContextUtil.getBean("xxx");
其中工具类为
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
public static Object getBean(Class c) {
return applicationContext.getBean(c);
}
}
修改完成后重新上线bug解决
问题总结:其一主要原因是没有搞懂new ClassPathXmlApplicationContext("xx.xml")获取配置中的数据库连接池中的连接connection时,需要保障该代码全程只能执行一次,否则问题很严重。其二是项目经手人比较多,导致不统一由Spring托管bean,最终需要使用jdbc代码获取connection。