数据库连接池耗尽 - Java

时间:2013-08-06 09:08:05

标签: java postgresql connection-pooling

我在我的应用程序中使用连接池(snaq.db.ConnectionPool)。连接池初始化为:

String dburl = propertyUtil.getProperty("dburl");
String dbuserName = propertyUtil.getProperty("dbuserName");
String dbpassword = propertyUtil.getProperty("dbpassword");
String dbclass = propertyUtil.getProperty("dbclass");
String dbpoolName = propertyUtil.getProperty("dbpoolName");
int dbminPool = Integer.parseInt(propertyUtil.getProperty("dbminPool"));
int dbmaxPool = Integer.parseInt(propertyUtil.getProperty("dbmaxPool"));
int dbmaxSize = Integer.parseInt(propertyUtil.getProperty("dbmaxSize"));
long dbidletimeout = Long.parseLong(propertyUtil.getProperty("dbidletimeout"));
Class.forName(dbclass).newInstance();
ConnectionPool moPool = new ConnectionPool(dbpoolName, dbminPool, dbmaxPool, dbmaxSize,
dbidletimeout, dburl, dbuserName, dbpassword);

使用的DB池值是:

dbminPool=5
dbmaxPool=30
dbmaxSize=30
dbclass=org.postgresql.Driver
dbidletimeout=25

我的应用程序正在某处泄漏连接(连接未被释放),并且由于连接池已经耗尽。我现在已修复该代码。

空闲超时后不应关闭连接?如果这是不正确的假设,有没有办法关闭开放空闲连接(仅通过java代码)?

5 个答案:

答案 0 :(得分:3)

您没有发布完整的代码,因此我假设您没有关闭连接。您仍然需要关闭从池中获取的连接对象,就像您没有使用池一样。关闭连接使池可以重新发出给另一个调用者。如果您未能执行此操作,最终将使用池中的所有可用连接。池的陈旧连接清除器不是清理连接的最佳位置。就像你的妈妈告诉你的那样,当你完成它们时,把你的东西拿走。

try {
  conn = moPool.getConnection(timeout);
  if (conn != null)
    // do something
} catch (Exception e) {
  // deal with me
} finally {
  try { 
    conn.close(); 
  } catch (Exception e) { 
    // maybe deal with me
  }
}
  • 电子

答案 1 :(得分:3)

timeout变量似乎不对应于连接空闲的时间,而是对应于池等待返回新连接或抛出异常的时间(我看了{{3} ,不知道它是否是最新的)。我认为跟踪“空闲”连接是相当困难的,因为在这种情况下“空闲”真正意味着什么?您可能希望获得连接以供以后使用。所以我想说连接池唯一的安全方式就是知道你完成了连接,就是在它上面调用close()

如果您担心开发团队忘记在他们的代码中调用close(),我会在下面介绍一种技术,我过去曾使用过(在我的情况下,我们希望跟踪未关闭的{ {1}}但是概念是一样的。)

免责声明:

  • 我假设连接仅在单个请求期间使用,并且在连续请求期间不会跨越。在后一种情况下,您无法使用下面的解决方案。
  • 您的连接池实现似乎已经使用了与我在下面描述的技术类似的技术(即它已经包装了连接),所以我不可能知道这是否适用于您的情况。我没有测试下面的代码,我只是用它来描述这个概念。
  • 请仅在您的开发环境中使用它。在生产中,您应该确信您的代码已经过测试并且行为正确。

如上所述,主要思想是:我们有一个中心位置(连接池),我们从中获取资源(连接),我们希望跟踪我们的代码是否释放了这些资源。我们可以使用使用InputStream对象的网络Filter来跟踪请求期间使用的连接。我将此类命名为ThreadLocal,并且跟踪资源的对象是TrackingFilter类。

Tracker

要使public class TrackingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { Tracker.start(); try { chain.doFilter(request, response); } finally { Tracker.stop(); } } ... } 能够跟踪连接,每次使用Tracker获取连接时以及每次使用{{1}关闭连接时都需要通知打电话。为了能够以对代码的其余部分透明的方式执行此操作,我们需要包装getConnection()和返回的close()对象。您的代码应该返回新的ConnectionPool而不是原始池(我假设访问连接池的方式是在一个地方)。这个新池将依次包含它提供的每个Connection,作为TrackingConnectionPoolConnection是知道如何在创建时和关闭时通知我们TrackableConnection的对象。

当您在请求结束时致电TrackableConnection时,它会报告尚未调用Tracker的任何连接。由于这是一个按请求操作,因此您只能识别错误操作(即在“创建新产品”功能期间),然后希望您能够跟踪那些留下开放连接并修复它们的查询。

您可以在下面找到Tracker.stop()close()TrackingConnectionPool课程的代码和评论。为简洁起见,遗漏了代表方法。我希望有所帮助。

注意:对于包装器使用自动IDE功能(如Eclipse的“生成委托方法”),否则这将是一项耗时且容易出错的任务。

TrackableConnection

答案 2 :(得分:1)

连接池的重点是让pool为你处理所有这些事情。

  • 拥有closing open idle connections of java pool的代码对您的情况无济于事。
  • 考虑为IDLEIN-USE连接维护MAP的连接池。
  • IN-USE:如果应用程序正在引用连接对象,则会按池将其放入in-use-map
  • IDLE:如果应用程序/或closed未引用连接对象,则会按池将其放入idle-map
  • 你的游泳池因为你没有关闭连接而筋疲力尽。未关闭连接会导致所有idle个关联都放入in-use-map
  • 由于idle-pool没有任何可用条目,因此强制池会创建更多条目。
  • 通过这种方式,您的所有连接都标记为IN-USE
  • 您的游泳池没有任何open-idle-connections,您可以通过代码关闭它。
  • 即使发生超时,池也无法关闭任何连接,因为没有空闲。

当您修复代码中的连接泄漏时,您已尽力而为。

您可以force发布池并重新创建一个。但是您必须小心,因为现有的连接可能会在其任务中受到影响。

答案 3 :(得分:0)

在大多数连接池中,空闲超时是连接池在连接池中空闲的最长时间(等待请求),而不是它在使用多长时间(从连接池中检出)。

某些连接池还具有允许连接使用多长时间的超时设置(例如,DBCP具有removeAbandonedTimeout,c3p0具有unreturnedConnectionTimeout),如果已启用并且超时已过期,他们将被强制撤销用户,并返回游泳池或真正关闭。

答案 4 :(得分:0)

log4jdbc可用于通过jdbc.connection记录器缓解连接泄漏问题。

此技术不需要对代码进行任何修改。