除非我调用Connection.commit()
,否则数据库游标在查询后保持打开状态。我相信此行为会导致我的应用程序泄漏游标并遇到与游标使用相关的数据库错误。
看来commit()
电话应该是不必要的...这种行为是预期的吗?有没有办法将 JDBC 连接池配置为在资源关闭时可靠地释放游标,而无需调用 commit?
我正在使用此查询来查找打开的游标:
select * from v$open_cursor where CURSOR_TYPE = 'OPEN'
如果我在关闭statement
并ResultSet
后调用commit()
,则在sleep()
期间没有打开游标
try (Connection con = pooledDataSource.getConnection()) {
try (PreparedStatement statement = con.prepareStatement("select 1 from dual a");
ResultSet rs = statement.executeQuery()) {
}
con.commit();
}
Thread.sleep(20000);
如果我在关闭 statement
和 ResultSet
之前调用 commit ,当我在 sleep(( 期间查询打开的游标时,我会发现 sql select 1 from b
。
try (Connection con = pooledDataSource.getConnection();
PreparedStatement statement = con.prepareStatement("select 1 from dual b");
ResultSet rs = statement.executeQuery()) {{
con.commit();
}}
Thread.sleep(20000);
这里也是一样。如果我不调用commit()
我会在我的打开游标查询中找到"从双 c 中选择 1",该查询在 JVM 退出之前保持打开状态。
try (Connection con = pooledDataSource.getConnection();
PreparedStatement statement = con.prepareStatement("select 1 from dual c");
ResultSet rs = statement.executeQuery()) {{
}}
这些是我的配置
PoolDataSource pooledDataSource = PoolDataSourceFactory.getPoolDataSource();
pooledDataSource.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pooledDataSource.setURL("jdbc:oracle:thin:@//" + host + ":1521/" + service);
pooledDataSource.setUser(user);
pooledDataSource.setPassword(pw);
pooledDataSource.setInitialPoolSize(1);
pooledDataSource.setMinPoolSize(1);
pooledDataSource.setMaxPoolSize(1);
pooledDataSource.setAbandonedConnectionTimeout(5);
pooledDataSource.setConnectionWaitTimeout(5);
pooledDataSource.setInactiveConnectionTimeout(5);
此行为不会在使用以下测试 UCPTest.java 的 12.2.0.1(JDBC 下载页面(中重现。无论如何,请注意这不是错误。您观察到的是由于司机在声明关闭时不会往返。相反,该操作在下一次往返时被捎带。这是一项优化,旨在减少客户端和服务器之间的往返总数。之所以在 12.2.0.1 中没有观察到相同的行为,是因为 UCP 在将连接释放到池时对数据库进行单向访问,并刷新了背负调用。如果您想人为地冲洗背负式呼叫,您也可以这样做 ((oracle.jdbc.OracleConnection)con).pingDatabase()
这是一个完整的往返,因此会进行捎带呼叫的队列。