昨天在測試的時候,經常出現一個異常:Error setting up static cursor cache 網上說這是因爲一個進程所持有的File Descriptor 過多引起的。我查了一個下午,發現是由於微軟提供的SQL Server JDBC驅動引起的,但是確實是我們自己編碼的失誤,沒有關閉一些相應的資源。
在系統中,錯誤隱藏很深,我試驗了多次,終於重現了錯誤,代碼如下:
try
{
Connection conn = ........ //注意,該連接可能是從連接池中獲取的
DatabaseMetaData dbm = conn.getMetaData();
//得到信息源中的所有的表的
for (int i = 0; i < 100; i++)
{
long start = System.currentTimeMillis();
//得到信息源中的所有的表的
ResultSet rs = dbm.getTables(null, null, null, new String[]
{"TABLE"});
while (rs.next())
{
String tableName = rs.getString(3); //得到表的名稱
ResultSet rs1 = dbm.getColumns(null, null, tableName, null);
while (rs1.next())
{
rs1.getString(4);
}
ResultSet rs2 = dbm.getImportedKeys(null, null, tableName);
while (rs2.next())
{
rs2.getString(4);
}
ResultSet rs3 = dbm.getExportedKeys(null, null, tableName);
while (rs3.next())
{
rs3.getString(8);
}
ResultSet rs4 = dbm.getPrimaryKeys(null, null, tableName);
while (rs4.next())
{
rs4.getString(4);
}
}
long end = System.currentTimeMillis();
System.out.println(">>>>"+i+": " + (end - start));
}
conn.close(); //這裏的close方法,並不真正的關閉連接,只是把它放到了 緩衝池中
}
catch (SQLException e)
{
e.printStackTrace();
}
}
上述代碼獲取一個數據庫的所有表,表的主鍵、外鍵等信息,在我機器上for循環每到第58次就會出現錯誤。原因如下:
SQLServer JDBC爲了獲得這些數據,會使用大量臨時文件(在java.io.tmpdir指定的目錄中),但是如果不關閉ResuletSet的話(例如上面的代碼),JDBC就不會釋放這些文件的Hanlder, 所以當獲取數據庫Schema次數較多時,,當前的進程會持有大量的文件Hanlder, 這時候,JDBC就會拋出"Error setting up static cursor cache"的異常。
所以ResultSet如果不用的話,一定要記着關閉,否則後患無窮