2012-06-01 93 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