关闭结果集后,Oracle不删除游标


问题内容

注意:我们重复使用单个连接。

************************************************
public Connection connection() {        
    try {
        if ((connection == null) || (connection.isClosed()))
        {
            if (connection!=null)
                log.severe("Connection was closed !");
            connection = DriverManager.getConnection(jdbcURL, username, password);
        }
    } catch (SQLException e) {
        log.severe("can't connect: " + e.getMessage());
    }
    return connection;        
}
**************************************************

public IngisObject[] select(String query, String idColumnName, String[] columns) {
    Connection con = connection();

    Vector<IngisObject> objects = new Vector<IngisObject>();
    try {
        Statement stmt = con.createStatement();

        String sql = query;
        ResultSet rs =stmt.executeQuery(sql);//oracle increases cursors count here
        while(rs.next()) {
            IngisObject o = new IngisObject("New Result");
            o.setIdColumnName(idColumnName);            
            o.setDatabase(this);
            for(String column: columns)
                o.attrs().put(column, rs.getObject(column));
            objects.add(o);
        }

        rs.close();// oracle don't decrease cursor count here, while it's expected
        stmt.close();
    } 
    catch (SQLException ex) {
        System.out.println(query);
        ex.printStackTrace();
    }

问题答案:

init.ora参数open_cursors定义会话一次可以拥有的打开的游标的最大值。它的默认值为50。如果应用程序超出此数目,则会引发错误“
ORA-01000:最大打开游标超过”。

因此,当不再需要JDBC资源(尤其是java.sql.ResultSet和java.sql.Statement)时,必须关闭它们。如果未关闭它们,则应用程序会发生资源泄漏。

在重用Connection对象的情况下,您必须意识到以下事实:打开的oracle游标会保持打开状态并在使用中,只要连接存在
事务尚未结束。应用程序提交时,将释放打开的游标。

因此,作为应用程序设计师,您需要了解最复杂事务所需的打开游标的粗略估计。

困难在于oracle的内部参数视图(v $ open_cursor,v $
sesstat等)无法显示已打开的游标(可重复使用)和已打开的游标(仍被阻止(不可重用!))之间的差异。未封闭的ResulSet或Statement。如果您关闭了finally块中的所有Statement和ResultSet对象,则您的应用程序将非常好。

调整init.ora参数的工作原理如下(我们的应用程序最多需要800个游标)

ALTER SYSTEM SET open_cursors = 800 SCOPE=BOTH;