2010-11-03 111 views
2

在使用SQLIte来保存数据的java应用程序的上下文中,我使用的是Zentus JDBC驱动程序。因此我使用java.sql包来访问我的数据库。是否有任何工具或技术来识别打开的ResultSet

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

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

编辑可能会使用AspectJ ??

回答

3

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

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

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

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

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

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

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

1

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

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

这个例子展示我如何实现在终于接近(用于担保)关闭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美分的价值...希望它可以帮助你。

+0

感谢您的JAMon外观。 “检查代码并确保所有Statement,PreparedStatement和ResultSet都关闭”的手动解决方案是无聊的;-),我想避免它。 – 2010-11-03 12:15:27

+0

使用工具管理打开的游标也不是那么容易。你需要做的一件事就是看看这些游标是否正在使用或停滞不前,这很难说清楚。 – 2010-11-03 12:37:19

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 

打开与CSV文件Excel或任何其他电子表格程序,排序表并查看结果集是否未关闭。如果是这种情况,请添加更多调试信息以清楚地标识打开的设置。


BTW - 包装纸接口(如火腿)是很容易的,如果你有偏食或别的东西,它在不到15分钟的编码。你需要包装连接,语句(和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)); 
+0

我的问题是我有很多调用stmt.executeQuery,因此我正在寻找一种方法来避免必须手动检查代码并确保所有Statement,PreparedStatement和ResultSet都已关闭。 Manu – 2010-11-03 12:14:32

+0

不是一个坏主意! @Andreas_D – 2010-11-03 12:40:18

1

它应该是相对简单的仪器与您选择的AOP代码。我在多年前使用AspectWerkz数字来完成Web应用程序的加载时间编织并收集与性能相关的统计信息。另外,如果您使用的是IOC框架(如Spring),则可以很容易地将DataSources和跟踪调用包装到getConnection()等。

相关问题