spring中的数据库连接池泄露

数据库连接池泄露的问题,在JAVA开发中,是我们一直要面对的问题。但是呢,这种问题一般都是在很久很久以前的开发中,自从我们使用了hibernate或者spring的框架之后。数据库连接泄露的问题,好像基本上就消失了。 一般的轻量级应用,就算有一些轻微泄露,如果访问量强度不够,那么这个问题确实不显著; 但是有的应用的数据库访问强度相当的高,一点点的泄露,最终都能把整个系统打爆。

使用了spring这些框架,能够大幅度降低数据量链接泄露的问题的出现概率,但是并不是真的就彻底让这些泄露这种问题消失了,一旦发生数据库连接池泄露,要查找这些问题,并不容易,因为很多人已经不知道这个事情是怎么发生的。 这种隐藏的错误是非常难被发现的。

1) 前提和准备 我们需要利用log4j的info模式来观察,因此我们需要系统能支持log4j运行; 我们需要观察事务,,因此我们要访问一个数据库。

create table FFM_USER( USERNAMEVARCHAR2(64), PASSWORDVARCHAR2(64), LAST_LOGON_TIME VARCHAR2(64), CHARGEINTEGER)

里面有一条数据: 在username字段对应“ffm”

2) 业务场景 利用多线程启动多个UserService里面的方法,故意写了一个能够造成数据库连接池泄露的样例。 注意:不要在实际项目中这样使用

3) 实现spring框架下数据库连接池泄露的源代码 实现类

package com.spring.jdbc;import java.sql.Connection;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;/** * 模拟在spring框架下的数据库连接泄露 * @author 范芳铭 */ @Service(“userService”){@Autowired private JdbcTemplate jdbcTemplate;(String userName){try{//下面这个语句会造成数据库连接池泄露【 标注A】Connection conn = jdbcTemplate.getDataSource().getConnection();String sql = “update ffm_user u set u.last_logon_time = ? where username =? “;jdbcTemplate.update(sql, System.currentTimeMillis(),userName);Thread.sleep(1000);//如果使用了【 标注A】,必须明显调用close方法//conn.close();}catch(Exception e){e.printStackTrace();}}}

利用多线程启动数据库连接池泄露

package com.spring.jdbc;import org.apache.commons.dbcp.BasicDataSource;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import org.springframework.stereotype.Service;/** * 模拟在spring框架下的数据库连接泄露 * * @author 范芳铭 */ @Service(“jdbcLeakService”){(UserService userService,String username){UserThread thread = new UserThread(userService,username);thread.start();}(long time){try{Thread.sleep(time);}catch(Exception e){e.printStackTrace();}}{private UserService userService;private String username;private UserThread(UserService userService,String username){this.userService = userService;this.username = username;}(){try{userService.logon(username);}catch(Exception e ){e.printStackTrace();}}}(BasicDataSource basicDataSource){System.out.println(“当前连接数【活跃的:空闲的】:” + basicDataSource.getNumActive() + “:” +basicDataSource.getNumIdle());}(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext(“b_jdbc.xml”);UserService service = (UserService)ctx.getBean(“userService”);BasicDataSource basicDataSource = (BasicDataSource)ctx.getBean(“dataSource”);EasyJdbcLeak.getConnNum(basicDataSource);EasyJdbcLeak.asynchThreadAdd(service, “ffm”);EasyJdbcLeak.sleep(500);EasyJdbcLeak.getConnNum(basicDataSource);EasyJdbcLeak.asynchThreadAdd(service, “ffm”);EasyJdbcLeak.sleep(1000);EasyJdbcLeak.getConnNum(basicDataSource);EasyJdbcLeak.asynchThreadAdd(service, “ffm”);EasyJdbcLeak.sleep(1500);EasyJdbcLeak.getConnNum(basicDataSource);}}

4)配置文件b_jdbc.xml

====”http://www.springframework.org/schema/task”xsi:schemaLocation=””>== “dataSource” class=”org.apache.commons.dbcp.BasicDataSource”destroy-method = “close”=”${jdbc.o2o.username}”p:password=”${jdbc.o2o.password}” />=>

5)运行系统 开启INFO模式,启动“模拟容器运行”应用。查看日志。 当前连接数【活跃的:空闲的】:0:0 当前连接数【活跃的:空闲的】:0:0 当前连接数【活跃的:空闲的】:2:2 当前连接数【活跃的:空闲的】:3:1 活跃的数据库连接数越来越多,几乎不会被释放,当连接数用完之后,系统就会出问题。

解决spring数据库连接池泄露的方法 //如果使用了【 标注A】,必须明显调用close方法 //conn.close();

人之所以能,是相信能。

spring中的数据库连接池泄露

相关文章:

你感兴趣的文章:

标签云: