有没有任何工具或技术可以识别打开的结果集

发布于 2024-09-30 14:09:37 字数 482 浏览 0 评论 0原文

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

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

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

编辑可能正在使用AspectJ

In the context of a java application using SQLIte to persist data I am using the Zentus JDBC driver. Thus I am using the java.sql package to acces my database.

I am facing some strange (in a an environment with several Connection objects on the same database) issues and I am pretty sure my problems come from non closed ResultSet.

Is there any tool or technique allowing me to spot where to look in my source code to find these non closed objects ?

Edit May be using AspectJ ??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冰葑 2024-10-07 14:09:37

看起来某个方面可能会有所帮助。

如何将返回结果集的方法包装在方面中。类似于:

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

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

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

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

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

It seems like an aspect may be helpful.

How about wrapping the methods which return a result set in an aspect. Something like:

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

Another aspect can monitor the close method on ResultSets. Perhaps:

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

The first aspect would, on the return of every ResultSet, create a new Exception object and store it in a static Map somewhere using the hash of the ResultSet as the key. The second aspect, on the closing of the result set, would remove the Exception from the Map using the same hashcode as a key. At any time, the map should have one exception instance for every open ResultSet. From the exception you can obtain a stack trace to see where the ResultSet was opened.

You could perhaps store a larger object which includes an exception and some other contextual information; time that the ResultSet was created, etc.

或十年 2024-10-07 14:09:37

一个实用的建议是添加一些调试代码并将结果集的创建和关闭“记录”到 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将返回包装的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
  }

  // ...
}

At 代码中的一行:

Connection con = DriverManager.getConnection(ur);

最后,您只需要修改

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

A practical suggestion is to add some debug code and "log" creation and closing of resultsets to a csv file. Later on you could examine this file and check, if there's a "close" entry for each "create".

So, assuming you have a utility class with static methods that allows writing Strings to a file, you can do it like this:

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

and

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

Open the csv file with Excel or any other spread sheet program, sort the table and look if result sets are not closed. If this is the case, add more debug information to clearly identify the open sets.


BTW - Wrapping the interfaces (like JAMon) is pretty easy, if you have eclipse or something else, its coded in less then 15 Minutes. You'd need to wrap Connection, Statement (and PreparedStatement?) and ResultSet, the ResultSet wrapper could be instrumented to track and monitor creation and closing of result sets:

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

  // ...
}

The same for MonitoredStatement and MonitoredResultSet (MonitoredStatement will return wrapped ResultSets):

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

  // ...
}

and

public MonitoredResultSet implements ResultSet {
  private ResultSet wrappedResultSet;

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

  // ...
}

At the end, you should only need to modify a single line in your code:

Connection con = DriverManager.getConnection(ur);

to

Connection con = new MonitoredConnection(DriverManager.getConnection(ur));
陌生 2024-10-07 14:09:37

Google 搜索直接将我指向 JAMon还允许您监视 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美分价值......希望它对你有帮助。

A Google Search pointed me directly to JAMon. It allows you to also monitor JDBC connections and cursors.

Personally, I would check the code and make sure that all Statement, PreparedStatement and ResultSet are closed when not needed. Even when using Connection Pooling, only JDBC Connection are returned into the pool and statements and ResultSet are closed.

This example shows how I achieve closing ResultSet and PreparedStatement in the finally close (for guarantee):

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

That's my 2 cents worth...hope it helps you.

紫瑟鸿黎 2024-10-07 14:09:37

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

It should be relatively simple to instrument your code with AOP of your choice. I was using AspectWerkz number of years ago to do load-time weaving of web app and collecting performance related statistics. Also if you're using IOC framework, such as Spring it's very easy to wrap your DataSources and trace calls to getConnection() etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文