Tomcat DBCP 连接池泄露

连接池泄露是指:应用一直持有数据库连接未释放,数据源一般都会配置maxActive属性以限制数据源使用的数据库连接的峰值,此时,当应用持有的连接数超过maxActive的值之后,将会报错,并使得服务器无法再响应需要访问数据库的请求

1 org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting foridle object
  at org.apache.tomcat.dbcp.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)

  at org.apache.tomcat.dbcp.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
   at com.wubiaoblog.probe.TestProbeServlet.doGet(TestProbeServlet.java:42)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

  at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
  at com.googlecode.psiprobe.Tomcat60AgentValve.invoke(Tomcat60AgentValve.java:30)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
  at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
  at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
  at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
  at java.lang.Thread.run(Thread.java:722)
  Caused by: java.util.NoSuchElementException: Timeout waiting foridle object
  at org.apache.tomcat.dbcp.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1167)
  at org.apache.tomcat.dbcp.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
   ...17more

与内存泄露类似,这是程序的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监控一下数据源状态:

leak1

三、问题修复

Tomcat官方的建议:http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html#Preventing_database_connection_pool_leaks

在数据源配置中增加三个参数:

<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之后可打印出具体发生泄露的代码

重启后再测

leak2

Log的提示很明显

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值