连接池泄露是指:应用一直持有数据库连接未释放,数据源一般都会配置maxActive属性以限制数据源使用的数据库连接的峰值,此时,当应用持有的连接数超过maxActive的值之后,将会报错,并使得服务器无法再响应需要访问数据库的请求:
与内存泄露类似,这是程序的bug!
一、环境
Jdk:jdk_1.7.0_03
Tomcat:apache-tomcat-6.0.35
OS:win7 64bit
Oracle:Enterprise Edition Release 11.2.0.1.0
Tomcat部署在本地,Oracle部署在192.168.1.220:1521
二、问题重现
由于发现这个问题是在生产环境,这里以最简单的测试环境来重现下这个问题。
2.1新建一个web工程
包含一个访问数据库的TestLeakServlet以及一个无需访问数据库的普通页面index.jsp。
2.2配置数据源
修改$CATALINA_HOME/conf/server.xml:
<Resource name=“jdbc/mydb” type=“javax.sql.DataSource” username=“scott” password=“tiger” driverClassName=“oracle.jdbc.driver.OracleDriver” url=“jdbc:oracle:thin:@192.168.1.220:1521:mydb” maxIdle=“2″ maxWait=“20″ maxActive=“10″ /> |
修改$CATALINA_HOME/conf/content.xml:
<ResourceLink global=”jdbc/mydb” name=”jdbc/mydb” type=”javax.sql.DataSource”/> |
2.3Servlet主要代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { System.out.println(“come on…”); try { Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup(“java:comp/env”); DataSource ds = (DataSource) envCtx.lookup(“jdbc/mydb”); Connection conn = ds.getConnection(); String sql = “select count(1) from dba_objects”; Statement statement = conn.createStatement(); ResultSet rs = statement.executeQuery(sql); rs.next(); System.out.println(rs.getInt(1)); } catch (SQLException e) { e.printStackTrace(); } catch (NamingException e) { e.printStackTrace(); } } |
Servlet中没有关闭连接。
2.4测试
启动服务后,重复访问10次TestLeakServlet,在第11次访问时,因为此时已经无法再获取数据库连接了,但是index.jsp是依然可以访问的,因为它不需要数据库连接。可以结合probe监控一下数据源状态:
三、问题修复
在数据源配置中增加三个参数:
<Resource name=”jdbc/mydb” type=”javax.sql.DataSource” username=”scott” password=”tiger” driverClassName=”oracle.jdbc.driver.OracleDriver” url=”jdbc:oracle:thin:@192.168.1.220:1521:mydb” maxIdle=”2″ maxWait=”20″ maxActive=”10″ removeAbandoned=”true” removeAbandonedTimeout=”10″ logAbandoned=”true” /> |
removeAbandoned表示是否删除超过removeAbandonedTimeout时间的废弃连接
removeAbandonedTimeout是一个时间阀值
logAbandoned表示是否打印相关log,这个很重要,默认是false,设置为true之后可打印出具体发生泄露的代码
重启后再测
Log的提示很明显