簡體   English   中英

多線程環境中的連接池超時問題

[英]connection pooling timeout problems in multithreading environment

我的團隊必須進行一些更改並更新舊的Web應用程序。 該應用程序具有一個主線程和5至15個守護程序線程,這些線程用作工作程序以在DB中檢索和插入數據。

所有這些線程都具有這種設計(為方便起見,此處進行了簡化):

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交互(某些類是靜態的)。 DataSource在服務器中配置。

public ThatDataAccessor {

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

問題是主線程需要連接到數據庫,並且當這些守護程序線程正在工作時,我們很容易用盡池中的可用連接,從而出現“等待連接超時”異常。 此外,有時甚至那些守護程序線程也會獲得相同的異常。

我們必須擺脫這個問題。

我們有一個配置有20個連接的連接池,由於“ 20”是我們的生產環境標准,因此無法添加。 即使我們計划僅將“ synchronized”關鍵字移到真正需要的地方,也需要同步一些代碼塊。 但是我認為這不會真正改變。

我們沒有多線程編程方面的經驗,並且以前從未遇到過連接池問題,這就是為什么我要問: 問題出在這些線程的設計上嗎? 有沒有我們沒有注意到的缺陷?

我已經逐一剖析了線程類,只要它們不是並行運行的,似乎沒有瓶頸可以證明那些“等待連接超時”。 該應用程序使用Oracle 11g在WebSphere 7上運行。

您可能在某個地方丟失了finally塊,無法將連接返回到池中。 使用休眠,我認為這可能在您調用close()時完成,或者對於事務(當您調用rollback()時)完成。 但是我還是會打電話給關閉。

例如,我自己編寫了一個快速且骯臟的池,以擴展一個舊應用程序以使其成為多線程,這是一些處理代碼(除了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塊是相當普遍的。例如,看一下這個休眠教程,然后跳到最底層的例子。 您會看到在try {}中他使用了tx.commit(),在catch {}中他使用了tx.rollback(),但是他沒有session.close(),並且最終也沒有。 因此,即使他在try和catch中添加了“ session.close()”,如果他的try塊拋出了RuntimeException以外的東西,或者他的catch在try之前引發了另一個異常,或者在rollback()之前引發了非HibernateException異常,他的聯系不會被關閉。 沒有session.close(),我認為這實際上不是很好的代碼。 但是,即使代碼似乎可以正常工作,最終也可以確保您免受此類問題的侵害。

因此,我將重寫他的使用Session來匹配休眠文檔頁面上顯示的慣用法的方法。 (而且我也不建議他拋出RuntimeException,但這是一個不同的主題)。

因此,如果您使用的是Hibernate,我認為以上內容就足夠了。 但是否則,如果需要特定的代碼幫助,則需要更加具體,但是否則,您應該使用finally確保連接關閉的簡單想法就足夠了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM