Oracle PoolDataSource将数据库游标保持打开直到commit(),这是预期的行为吗?

时间:2018-03-03 03:06:24

标签: java oracle jdbc

除非我调用Connection.commit(),否则数据库游标在查询后仍保持打开状态。我相信这种行为导致我的应用程序泄漏游标并遇到与游标使用相关的数据库错误。

似乎commit()调用似乎不必要......这种行为是否符合预期?有没有办法配置JDBC连接池,以便在资源关闭时可靠地释放游标,而无需调用commit?

我正在使用此查询来查找打开的游标:

select * from v$open_cursor where CURSOR_TYPE = 'OPEN'

如果我在关闭commit()statement后致电ResultSet,则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);

如果我在关闭statementResultSet之前调用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);

1 个答案:

答案 0 :(得分:2)

使用以下测试JDBC Download page,此行为不会在12.2.0.1(UCPTest.java)中重现。无论如何请注意,这不是一个错误。你观察到的是因为当一个陈述被关闭时,司机没有进行往返。相反,该操作将在下一次往返时捎带。这是一种优化,可以减少客户端和服务器之间的往返总数。您在12.2.0.1中没有观察到相同行为的原因是因为当连接释放到池并且刷新搭载调用时,UCP会对数据库进行单向访问。如果你想人为地冲洗背驮式电话,你也可以这样做 ((oracle.jdbc.OracleConnection)con).pingDatabase()这是一个完整的往返,因此携带背驮式呼叫队列。