昨天在测试的时候,经常出现一个异常: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如果不用的话,一定要记着关闭,否则后患无穷