2012-06-01 64 views
1

我的团队必须进行一些更改并更新旧的Web应用程序。这个应用程序有一个主线程和5到15个守护进程线程,用作工作者来检索和插入数据库中的数据。多线程环境中的连接池超时问题

所有这些线程有这样的设计(这里简化为方便起见):

public MyDaemon implements Runnable { 

    // initialization and some other stuffs 

    public void run() { 
     ... 
     while(isEnabled) { 
       Engine.doTask1(); 
       Engine.doTask2(); 
       ... 
       Thread.sleep(someTime); 
     } 
    } 
} 

引擎类提供了一系列用于maipulate DataAccessor类的其他方法静态方法,其中一些方法,一直静:

public Engine { 

    public static doTask1() { 
     ThisDataAccessor.retrieve(DataType data); 
     // some complicated operations 
     ThisDataAccessor.insertOrUpdate(DataType data); 
    } 

    public static doTask2() { 
     ThatDataAccessor da = new ThatDataAccessor(); 
     da.retrieve(DataType data); 
     // etc. 
    } 
    ... 
} 

DataAccessor类通常使用包含在同步方法中的简单JDBC语句(某些类为静态)与数据库进行交互。数据源在服务器中配置。

public ThatDataAccessor { 

    public synchronized void retrieve(DataType data) { 
     Connection conn = DataSource.getConnection(); 
     // JDBC stuff 
     conn.close(); 
    } 
    ... 
} 

问题是,主线程需要连接到数据库,当这些守护线程正在努力,我们很容易跑出来,从池中的可用连接,让“等待连接超时”异常。另外,有时甚至这些守护进程线程也会得到相同的异常。我们不得不摆脱这个问题。

我们有一个配置了20个连接的连接池,由于“20”是我们的生产环境标准,所以不能再添加任何连接池。一些代码块需要同步,即使我们计划只在真正需要的地方移动“synchronized”关键字。但我认为这不会造成真正的差异。

我们不是在多线程编程经验,我们从未遇到过这种连接前池的问题,这就是为什么我问:的问题是由于这些线程的设计?有没有我们没有注意到的缺陷?

我有一个一个的配置线程类,只要他们没有并行运行,似乎没有任何瓶颈来证明那些“等待连接超时”的理由。 该应用程序使用Oracle 11g在WebSphere 7上运行。

回答

1

您可能会错过某个地方的finally块以将连接返回到池中。有了休眠,我想这可能是在你调用rollback()时调用close()或可能用于事务时完成的。但是我会打电话关闭。

例如,我写了一个快速和肮脏的水池自己来扩展旧的应用程序,使其多线程,这里是一些处理代码(这应该是毫无意义的,你除了finnally块):

try { 
    connection = pool.getInstance(); 
    connection.beginTransaction(); 
    processFile(connection, ...); 
    connection.endTransaction(); 
    logger_multiThreaded.info("Done processing file: " + ...); 
} catch (IOException e) { 
    logger_multiThreaded.severe("Failed to process file: " + ...); 
    e.printStackTrace(); 
} finally { 
    if (connection != null) { 
     pool.releaseInstance(connection); 
    } 
} 

对于人们无法正确使用finally块的情况相当普遍......例如,查看this hibernate教程,并跳到最底层的示例。你会在try {}中使用tx.commit()并在catch {}中使用tx.rollback(),但他没有session.close(),最后也没有。所以即使他在try和catch中添加了“session.close()”,如果他的try块抛出了RuntimeException之外的其他东西,或者他的catch在try或non-HibernateException之前在rollback()之前导致了额外的Exception, ,他的联系不会被关闭。没有session.close(),我不认为这实际上是非常好的代码。但即使这些代码似乎在工作,最后也会保证您能够避免这类问题。

所以我会重写他的方法,使用Session来匹配this hibernate文档页面上显示的习惯用法。 (也不建议他抛出一个RuntimeException,但这是一个不同的话题)。

所以,如果你使用Hibernate,我认为上面已经足够好了。但是除此之外,如果你想要特定的代码帮助,你需要更具体一些,但是否则你应该使用finally来确保连接关闭的简单思想就足够了。

+0

我正在使用简单的JDBC,但我觉得问题与您所暴露的相似。代码的某些部分非常混乱,许多团队和开发人员都在努力,并且在某些情况下,我们发现了一些纠结和嵌套的try-catch块......我们将去寻找那些未关闭的连接,希望能够解决问题。 :) – javatutorial