【问题标题】:Is there any tool or technique to identify opened ResultSet是否有任何工具或技术来识别打开的 ResultSet
【发布时间】:2010-11-03 11:53:29
【问题描述】:

在使用SQLIte 保存数据的Java 应用程序上下文中,我使用的是Zentus JDBC 驱动程序。因此我使用java.sql 包来访问我的数据库。

我遇到了一些奇怪的问题(在同一个数据库上有多个 Connection 对象的环境中),我很确定我的问题来自未关闭的 ResultSet。

是否有任何工具或技术可以让我发现在我的源代码中查找这些非封闭对象的位置?

编辑可能正在使用 AspectJ ??

【问题讨论】:

    标签: java sql sqlite jdbc aspectj


    【解决方案1】:

    似乎某个方面可能会有所帮助。

    如何将返回结果集的方法包装在一个方面。比如:

    execution(public java.sql.ResultSet+ java.sql.Statement+.*(..))
    

    另一个方面可以监控 ResultSets 上的 close 方法。也许:

    execution(public * java.sql.ResultSet.close())
    

    第一个方面是,在每个 ResultSet 返回时,创建一个新的 Exception 对象,并使用 ResultSet 的哈希作为键将其存储在某个静态 Map 中。第二个方面,在关闭结果集时,将使用相同的哈希码作为键从 Map 中删除异常。在任何时候,地图都应该为每个打开的 ResultSet 提供一个异常实例。您可以从异常中获取堆栈跟踪以查看 ResultSet 的打开位置。

    您也许可以存储一个更大的对象,其中包括异常和一些其他上下文信息; ResultSet 的创建时间等。

    【讨论】:

      【解决方案2】:

      一个实用的建议是将一些调试代码和“记录”结果集的创建和关闭添加到 csv 文件中。稍后您可以检查此文件并检查每个“创建”是否有一个“关闭”条目。

      因此,假设您有一个带有静态方法的实用程序类,允许将字符串写入文件,您可以这样做:

       ResultSet rs = stmt.executeQuery(query);
       Util.writeln(rs.hashcode() + ";create"); // add this line whenever a 
                                               // new ResultSet is created
      

       rs.close();
       Util.writeln(rs.hashcode() + ";closed"); // add this line whenever a 
                                               // ResultSet is closed
      

      使用 Excel 或任何其他电子表格程序打开 csv 文件,对表格进行排序并查看结果集是否未关闭。如果是这种情况,请添加更多调试信息以清楚地识别开放集。


      顺便说一句 - 包装接口(如 JAMon)非常容易,如果你有 eclipse 或其他东西,它的编码时间不到 15 分钟。您需要包装 Connection、Statement(和 PreparedStatement?)和 ResultSet,ResultSet 包装器可以用于跟踪和监控结果集的创建和关闭:

      public MonitoredConnection implements Connection {
        Connection wrappedConnection = null;
      
        public MonitoredConnection(Connection wrappedConnection) {
          this.wrappedConnection = wrappedConnection;
        }
      
        // ... implement interface methods and delegate to the wrappedConnection
      
        @Override
        public Statement createStatement() {
          // we need MonitoredStatements because later we want MonitoredResultSets
          return new MonitoredStatement(wrappedConnection.createStatemet());
        }
      
        // ...
      }
      

      MonitoredStatement 和 MonitoredResultSet 相同(MonitoredStatement 将返回包装好的结果集):

      public MonitoredStatement implements Statement {
        private Statement wrappedStatement = null;
      
        @Override 
        public ResultSet executeQuery(String sql) throws SQLException
           MonitoredResultSet rs = wrappedStatement.executeQuery(sql);
           ResultSetMonitor.create(rs.getWrappedResultSet()); // some static utility class/method
           return rs;
        }
      
        // ...
      }
      

      public MonitoredResultSet implements ResultSet {
        private ResultSet wrappedResultSet;
      
        @Override 
        public void close() {
           wrappedResultSet.close();
           ResultSetMonitor.close(wrappedResultSet); // some static utility class/method
        }
      
        // ...
      }
      

      最后,您应该只需要修改代码中的一行:

      Connection con = DriverManager.getConnection(ur);
      

      Connection con = new MonitoredConnection(DriverManager.getConnection(ur));
      

      【讨论】:

      • 我的问题是我有很多对 stmt.executeQuery 的调用,因此我正在寻找一种方法来避免必须手动检查代码并确保所有 Statement、PreparedStatement 和 ResultSet关闭。马努
      【解决方案3】:

      Google Search 直接将我指向JAMonIt 还允许您监视 JDBC 连接和游标。

      就个人而言,我会检查代码并确保在不需要时关闭所有 StatementPreparedStatementResultSet。即使使用连接池,也只有 JDBC 连接返回到池中,语句和 ResultSet 被关闭。

      这个例子展示了我是如何在finally关闭(为了保证)中实现关闭ResultSet和PreparedStatement的:

      PreparedStatement ps = null;
      ResultSet rs = null;
      UserRequest request = null;
      
      try {
       ps = getConnection().prepareStatement(SQL_RETRIEVE);
       ps.setLong(1, id);
       rs = ps.executeQuery();
       if (rs != null && rs.next()) {
        request = mapEntity(rs);
       }
      } catch (SQLException e) {
       // TODO Auto-generated catch block
       throw new DAOException(e);
      } finally {
       try {
        close(rs, ps);
       } catch (SQLException e) {
        // TODO Auto-generated catch block
        logger.error("Error closing statement or resultset.", e);
       }
      }
      

      这是我的 2 美分价值...希望它对你有所帮助。

      【讨论】:

      • 感谢 JAMon 的外观。 “检查代码并确保所有 Statement、PreparedStatement 和 ResultSet 都已关闭”的手动解决方案很无聊 ;-) 我想避免它。
      • 使用工具管理打开的游标也不是那么容易。您必须做的一件事是查看这些游标是在使用中还是停滞不前,这并不容易判断。
      【解决方案4】:

      使用您选择的 AOP 来检测您的代码应该相对简单。几年前,我使用 AspectWerkz 对 Web 应用程序进行加载时编织并收集与性能相关的统计数据。此外,如果您使用的是 IOC 框架,例如 Spring,则很容易包装您的 DataSources 并跟踪对 getConnection() 等的调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-30
        • 1970-01-01
        • 2013-08-05
        • 1970-01-01
        • 1970-01-01
        • 2014-03-06
        • 2014-05-03
        • 2018-12-11
        相关资源
        最近更新 更多