【问题标题】:connection pooling timeout problems in multithreading environment多线程环境下的连接池超时问题
【发布时间】:2012-06-01 07:10:53
【问题描述】:

我的团队必须进行一些更改并更新旧的 Web 应用程序。此应用程序有一个主线程和 5 到 15 个守护线程,用作工作线程,用于在数据库中检索和插入数据。

所有这些线程都有这种设计(为方便起见,这里简化了):

public MyDaemon implements Runnable {

     // initialization and some other stuffs

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

Engine 类提供了一系列静态方法,用于处理 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 语句与 DB 交互。数据源在服务器中配置。

public ThatDataAccessor {

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

问题是主线程需要连接到数据库,当这些守护线程工作时,我们很容易用完池中的可用连接,出现“等待连接超时”异常。此外,有时甚至那些守护线程也会出现同样的异常。

我们必须摆脱这个问题。

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

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

我已经一一分析了线程类,只要它们不并行运行,似乎就没有瓶颈可以证明那些“等待连接超时”是合理的。 该应用程序使用 Oracle 11g 在 WebSphere 7 上运行。

【问题讨论】:

    标签: java multithreading connection-pooling


    【解决方案1】:

    您可能在某处丢失了 finally 块以将连接返回到池中。使用hibernate,我认为这可能在您调用close()时完成,或者可能在您调用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(),也没有 finally。因此,即使他在 try 和 catch 中添加了“session.close()”,如果他的 try 块抛出了 RuntimeException 以外的东西,或者他的 catch 在 try 之前导致了额外的异常,或者在 rollback() 之前导致了非 HibernateException ,他的连接不会关闭。如果没有 session.close(),我认为这实际上不是很好的代码。但是,即使代码看起来可以正常工作,a finally 也可以确保您免受此类问题的影响。

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

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

    【讨论】:

    • 我用的是简单的JDBC,但是感觉和你暴露的问题差不多。代码的某些部分非常混乱,许多团队和开发人员都在研究它,在某些情况下,我们发现了一些缠结和嵌套的 try-catch 块......我们将去寻找那些未关闭的连接,希望能解决问题。 :)
    猜你喜欢
    • 2010-09-24
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 2013-12-19
    • 1970-01-01
    相关资源
    最近更新 更多