2015-11-02 150 views
1

我有一個Java 7 Web應用程序堆棧,使用JBoss 7.1.3和ActiveMQ 5.11.1部署到集羣環境中。我使用Hibernate 4.0.1將我們的Java應用程序連接到RDS實例。休眠連接泄漏

我觀察到我們的環境似乎在泄露數據庫連接。在我們梳理我們的應用程序時,我們無法確定這些額外的數據庫連接可能來自哪裏。我們的hibernate連接壽命相對較短,並且總是在finally {}塊內關閉。

對數據庫使用查詢,我可以看到一個節點在20個連接處保持不變,另一個節點(主節點)的連接大小將緩慢增長。最終,這個數量增長很多,我們需要重新啓動該節點上的應用程序,這會觸發另一個節點的故障。然後該節點將開始連接增長,而新重新啓動的便箋將保持恆定爲20.

是否有可能碰到任何Hibernate的已知問題?有關如何正確調試此問題的任何建議?

謝謝。

更新1

我們使用定義爲連接池如下:

<datasource jta="true" jndi-name="java:jboss/datasources/MySqlDS" pool-name="MySqlIDS" enabled="true" use-java-context="true" use-ccm="true"> 
        <connection-url>jdbc:mysql://...</connection-url> 
        <driver>com.mysql</driver> 
        <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation> 
        <pool> 
         <min-pool-size>10</min-pool-size> 
         <max-pool-size>150</max-pool-size> 
         <prefill>true</prefill> 
         <use-strict-min>false</use-strict-min> 
         <flush-strategy>FailingConnectionOnly</flush-strategy> 
        </pool> 
        ... 
       </datasource> 

更新2

每次休眠使用forceCloseSessionInstance方法被稱爲它執行以下。

private void forceCloseSessionInstance() { 
     Session hsession = session.get(); 

if (hsession != null && hsession.isActive() && !hsession.wasRolledBack()) { 
      hsession.rollback(); 
     } 

     for(; ;) { 
      closeSessionInstance(); 
      if (session.get() == null) { 
       return; 
      } 
     } 
    } 

public void closeSessionInstance() throws HibernateException { 
     Integer level = transLevel.get(); 
     if (level == null) { 
      transLevel.set(0); 
      level = transLevel.get(); 
     } 
     if (level > 0) { 
      transLevel.set(level - 1); 
     } else { 
      Session s = session.get(); 
      session.set(null); 
      if (s != null) 
      { 
       if (s.isOpen()) 
       { 
        s.flush(); 
        s.clear(); 
        s.close(); 
       } 
      } 
     } 

    } 
+0

您使用連接池嗎? –

+2

Hibernate可能是罪魁禍首。然而,你的代碼被指責的可能性是1000倍。閱讀連接池中的文檔,它可能會跟蹤檢查時間過長的連接。 – Kayaman

+0

@ChrisThompson很好的問題,抱歉,不包括該信息。是的,我們正在使用泳池(最小尺寸10,最大尺寸150)。但是我們的應用程序似乎超過了150(如果我們讓它),並且我們開始獲取JDBC異常。 – Ternary

回答

1

您可以使用finally塊來指示在處理結束時想要發生什麼,而不管try-block內發生了什麼。但是如果你在你的finally塊中放置了多個東西,那麼如果事先引發異常,你可能會冒險讓finally塊中的東西不完整。下面就來寫JDBC代碼的常用方法,可能會導致連接泄漏:

try { 
    ... 
} finally { 
    resultSet.close(); 
    statement.close(); 
    connection.close(); 
} 

如果任何結果集或語句拋出當接近被稱爲(由於,比如說異常,JDBC對象試圖告訴數據庫服務器它可以釋放它爲該對象分配的資源,但發生網絡呃逆),則連接不會關閉。

與你的發佈代碼的共同性是有很多事情在你的清理中,如果任何事情發生錯誤,那麼會話不會被關閉。

的解決方案是通過嵌套finally塊來限制由一件事拋出讓其他事情要從例外的範圍被調用,例如:

try { 
    try { 
     try { 
      ... 
     } finally { 
      try { 
       resultSet.close(); 
      } catch (SQLException e) { 
       log.info(e); 
      } 
     } 
    } finally { 
     try { 
      statement.close(); 
     } catch (SQLException e) { 
      log.info(e); 
     } 
    } 
} finally { 
    try {  
     connection.close(); 
    } catch (SQLException e) { 
     log.info(e); 
    } 
} 

所以如果有什麼毛病內finally塊的外面的那些仍然被稱爲。此代碼還可以阻止關閉資源以屏蔽由try-block拋出的異常(因爲try-block引發的異常是具有有用信息的異常)所導致的異常。 (使用try-with-resources的工作方式大部分是相同的,只是如果try塊正常完成並且任何資源都拋出異常,那麼拋出close的異常不會被抑制。)