2010-02-08 222 views
83

我開始有點糊塗了,我是從http://en.wikipedia.org/wiki/Java_Database_Connectivity關閉數據庫連接

Connection conn = DriverManager.getConnection(
    "jdbc:somejdbcvendor:other data needed by some jdbc vendor", 
    "myLogin", 
    "myPassword"); 

Statement stmt = conn.createStatement(); 
try { 
    stmt.executeUpdate("INSERT INTO MyTable(name) VALUES ('my name') "); 
} finally { 
    //It's important to close the statement when you are done with it 
    stmt.close(); 
} 

閱讀下面你不需要關閉康恩連接? 如果conn.close()不會發生,那麼究竟發生了什麼?

我有一個私人的web應用程序,我堅持認爲當前不接近任何一種形式,但它是重要的一個真的語句之一,康涅狄格州一個,或兩者兼而有之?

該網站保持下去間歇但服務器一直說這是一個數據庫連接的問題,我懷疑的是,它沒有被關閉,但我不知道這是否任何關閉。

回答

150

當您完成使用Connection時,您需要通過調用其close()方法來明確地關閉它,以釋放連接可能持有的任何其他數據庫資源(遊標,句柄等)。

實際上,在Java的安全模式是關閉ResultSetStatement,並在finallyConnection(按順序)當你與他們類似的東西做:

Connection conn = null; 
PreparedStatement ps = null; 
ResultSet rs = null; 

try { 
    // Do stuff 
    ... 

} catch (SQLException ex) { 
    // Exception handling stuff 
    ... 
} finally { 
    if (rs != null) { 
     try { 
      rs.close(); 
     } catch (SQLException e) { /* ignored */} 
    } 
    if (ps != null) { 
     try { 
      ps.close(); 
     } catch (SQLException e) { /* ignored */} 
    } 
    if (conn != null) { 
     try { 
      conn.close(); 
     } catch (SQLException e) { /* ignored */} 
    } 
} 

finally塊可以稍微改善成(避免無效檢查):

} finally { 
    try { rs.close(); } catch (Exception e) { /* ignored */ } 
    try { ps.close(); } catch (Exception e) { /* ignored */ } 
    try { conn.close(); } catch (Exception e) { /* ignored */ } 
} 

但是,儘管如此,這是非常冗長,所以你通常最終使用的輔助類到c失去了對象空安全的輔助方法和finally塊變成這樣的事情:

} finally { 
    DbUtils.closeQuietly(rs); 
    DbUtils.closeQuietly(ps); 
    DbUtils.closeQuietly(conn); 
} 

而且,實際上,Apache Commons DbUtilsDbUtils類正是這樣做的,所以沒有必要寫你自己的。

+3

真棒幫助,謝謝!我沒有理解或想到conn!= null語句。 – onaclov2000 2010-02-08 22:17:01

+1

@ onaclov2000是的,'rs','ps','conn'可能是null,這取決於代碼的中斷位置。這就是爲什麼這被稱爲「安全」模式。 – 2010-02-08 22:53:38

+10

@Pascal Thivent:其實我們並不需要關閉所有這些。 「核心Java第二卷 - 高級功能」一書中寫道:如果語句有一個開放的結果集,Statement對象的'close'方法會自動關閉相關的'ResultSet'。類似地,'Connection'類的'close'方法關閉'Connection'的所有'語句'。 – 2011-07-12 12:13:48

6

是的,你需要關閉連接。否則,數據庫客戶端通常會保持套接字連接和其他資源處於打開狀態。

+0

...直到它退出。這將客戶端和服務器端的各種有限資源捆綁在一起。如果客戶端太多地執行這種事情,它可能會導致客戶端本身,數據庫服務以及甚至可能在客戶端或服務器上運行的其他應用程序出現問題。 – 2010-02-09 00:53:02

8

是的。您需要關閉結果集,語句和連接。如果連接來自池,關閉它實際上會將其發送回池以供重用。

您通常必須在finally{}塊中執行此操作,以便如果拋出異常,您仍然有機會關閉它。

許多框架都會爲你處理這個資源分配/釋放問題。例如春天的JdbcTemplateApache DbUtils有關閉結果集/語句/連接的方法,無論是否爲null(並在關閉時捕獲異常),這也可能有所幫助。

+0

當我插入一個「終於」的日食喜歡突出它告訴我這是錯誤的。這應該追趕擋塊嗎? – onaclov2000 2010-02-08 22:10:46

+2

廢話,我只是回答了我自己的問題,並嘗試過,對不起 – onaclov2000 2010-02-08 22:11:11

+0

是的。嘗試{}趕上{}終於{}。 catch {}是可選的,順便說一句。就像finally {} – 2010-02-08 22:11:36

9

只需關閉StatementConnection即可。沒有必要明確關閉ResultSet對象。

Java文檔說,大約java.sql.ResultSet

一個結果對象是由產生它時Statement對象被關閉時,重新執行,或用於檢索從下一個結果Statement對象自動關閉多個結果的序列。


感謝BalusC徵求意見:「我不會依賴於一些JDBC驅動程序失敗上。」

+14

我不會依賴那個。有些JDBC驅動程序會因此而失敗。例如。帶有「超過最大打開遊標數」的Oracle等。只需明確關閉所有打開的資源,不要找藉口。 – BalusC 2013-01-05 21:41:55

41

使用後關閉數據庫/資源​​對象通常會更好。 更好地關閉finally塊中的連接,結果集和語句對象。

在Java7之前,需要使用finally塊關閉所有這些資源。 如果您正在使用Java 7,則可以按如下方式關閉資源。

try(Connection con = getConnection(url, username, password, "org.postgresql.Driver"); 
    Statement stmt = con.createStatement(); 
    ResultSet rs = stmt.executeQuery(sql); 
) { 

//statements 
}catch(....){} 

現在,con,stmt和rs對象成爲try塊的一部分,java在使用後自動關閉這些資源。

希望我是有幫助的。

+0

如果我的語句是隱含的,例如''ResultSet rs = conn.createStatement()。executeQuery(sql);''try''塊內部怎麼辦? – Antares42 2015-10-12 08:13:55

+1

您將無法在finally {}塊中引用它們以關閉。如果拋出異常,ResultSet的close()方法將永遠不會被調用 – Dan 2016-10-30 06:42:28

0

實際上,如果您使用try-with-resources模塊,Java會在您退出try模塊時關閉所有連接。

您應該對任何實現AutoClosable的對象執行此操作。

try (Connection connection = getDatabaseConnection(); Statement statement = connection.createStatement()) { 
    String sqlToExecute = "SELECT * FROM persons"; 
    try (ResultSet resultSet = statement.execute(sqlToExecute)) { 
     if (resultSet.next()) { 
      System.out.println(resultSet.getString("name"); 
     } 
    } 
} catch (SQLException e) { 
    System.out.println("Failed to select persons."); 
} 

對getDatabaseConnection的調用剛剛組成。將其替換爲一個調用,該調用爲您提供JDBC SQL連接或來自池的連接。