如果你不使用連接池,那麼就沒有什麼問題,一旦Connection關閉,數據庫物理連接就被釋放,所有相關Java資源也可以被GC回收了。但是如果你使用連接池,那麼請注意,Connection關閉並不是物理關閉,只是歸還連接池,所以PreparedStatement和ResultSet都被持有,並且實際佔用相關的數據庫的遊標資源,在這種情況下,只要長期運行,往往就會報“遊標超出數據庫允許的最大值”的錯誤,導致程序無法正常訪問數據庫。
在使用java開發後臺應用程序的時候,如果需要使用數據庫,特別是試用第三方的數據庫連接池的時候,使用完PreparedStatement等一定要手動關閉,最好是將關閉的代碼寫到finally中,保證一定能夠完成關閉。
原因有如下兩點:
1、第三方的數據庫連接池,使用的時候,獲取到Connection之後,使用完成,調用的關閉方法(close()) ,並沒有將Connection關閉,只是放回到連接池中,如果調用的這個方法,而沒有手動關閉PreparedStatement等,則這個PreparedStatement並沒有關閉,這樣會使得開發的程序內存急速增長,java的內存回收機制可能跟不上速度,最終造成Out of memory Error。
2、如過在PreparedStatement等調用的時候,發生異常,則這個PreparedStatement是沒有被關閉的,因此最好將PreparedStatement等的關閉寫到finally代碼中。下面是本人
在本機上試過的一個測試實例
public static List<OrgzMetaDto> queryMetaByOrgzName1() {
String sql = "SELECT * FROM test_table limit 0, 10000";
List<OrgzMetaDto> orgzs = new ArrayList<OrgzMetaDto>();
try {
pst = conn.prepareStatement(sql);
ResultSet resultSet = pst.executeQuery();
while (resultSet.next()) {
OrgzMetaDto dto = new OrgzMetaDto();
dto.setUuid(resultSet.getString("uuid"));
orgzs.add(dto);
}
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
return orgzs;
}
public static void main(String[] args) throws Exception {
for (int i=0; i<1000; i++) {
System.out.println(i);
queryMetaByOrgzName1();
}
}
可以自行用類似於上述的代碼測試一下 , 測試的時候關注本機物理內存的佔用狀況
在有resultSet.close()這句代碼的時候,內存佔用並不會發生太大變化,而一旦不關閉結果集,內存佔用將會急速增長,甚至程序被hang住,我猜測可能就是上述所說的“遊標超出數據庫允許的最大值”,就算不阻塞,內存佔用繼續增長,將出現內存溢出問題