是否有任何工具或技术来识别打开的ResultSet

时间:2010-11-03 11:53:30

标签: java sql sqlite jdbc aspectj

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

我面临一些奇怪的问题(在同一个数据库中有多个Connection对象的环境中)问题,我很确定我的问题来自非封闭的ResultSet。

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

修改可能正在使用 AspectJ ??

4 个答案:

答案 0 :(得分:3)

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

如何在一个方面包装返回结果集的方法。类似的东西:

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

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

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

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

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

答案 1 :(得分:2)

一个实际的建议是添加一些调试代码和“log”创建和关闭结果集到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文件,对表格进行排序并查看结果集是否未关闭。如果是这种情况,请添加更多调试信息以清楚地识别开放集。


BTW - 包装界面(如JAMon)非常简单,如果你有日食或其他东西,它的编码时间不到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将返回包装的ResultSet)相同:

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));

答案 2 :(得分:1)

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

就个人而言,我会检查代码并确保在不需要时关闭所有语句 PreparedStatement ResultSet 。即使使用连接池,也只会将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美分价值......希望它可以帮到你。

答案 3 :(得分:1)

使用您选择的AOP来设置代码应该相对简单。我在几年前使用AspectWerkz进行Web应用程序的加载时编织并收集与性能相关的统计信息。此外,如果您正在使用IOC框架,例如Spring,则可以很容易地将您的DataSource和跟踪调用包装到getConnection()等。