从 Oracle DB 获取可滚动的结果集

Posted

技术标签:

【中文标题】从 Oracle DB 获取可滚动的结果集【英文标题】:Getting Scrollable Resultsets from Oracle DB 【发布时间】:2016-07-10 20:01:25 【问题描述】:

我们的团队正在与使用jdbcOracle 数据库服务器紧密合作。在我们的一项更改中,我调用了一个存储过程,它返回了两个不同的ResultSets。起初我的实现假定默认滚动能力。 失败后,我上网查了一下。

我能读到的所有关于它的内容基本上都是一样的:使用 prepareStatementprepareCall 方法以及适当的 TYPE_SCROLL_INSENSITIVECONCUR_READ_ONLY。这些都不起作用。

我使用的存储过程再次返回两个不同的结果集,它们是通过(ResultSet) rs.getObject("name") 提取的。通常在示例中,他们的 ResultSet 会立即从 .executeQuery 返回。 我的问题是,prepareCall 方法中的 Scrollablility/Updatability 类型会影响这些类型的 ResultSet 吗?如果是这样,我如何获得它们

我知道 JDBC 驱动程序会降低我对 ScrollableResultSet 的请求。 如何判断我的 ResultSet 是否已降级?

关于这一点,为什么默认情况下 ResultSet 不能滚动?最佳做法是什么?其灵活性的“成本”是多少?

【问题讨论】:

【参考方案1】:

在 Oracle 中,游标是只进的结构。所有数据库都知道如何获取下一行(嗯,技术上是下 n 行)。为了使 ResultSet 看起来可滚动,您需要依赖 JDBC 驱动程序。

JDBC 驱动程序有两种使 ResultSet 看起来可滚动的基本方法。第一个是在您获取数据时将整个结果集保存在内存中,以防万一您想倒退。从功能上讲,这是可行的,但当查询可能返回大量数据时,它可能会对性能和可伸缩性造成灾难性后果。当某段代码第一次开始占用应用服务器上 GB 的 RAM 时,因为查询返回了包含大量长注释字段的数千行,该 JDBC 驱动程序将被正确地称为资源消耗。

更常见的方法是让驱动程序向查询中添加一个键,并使用该键来管理驱动程序缓存的数据。因此,例如,驱动程序可能会将最后 1000 行完整地保留在内存中,但只缓存较早行的键,以便稍后返回并重新获取该数据。这对代码来说更复杂,但它也要求 ResultSet 有一个唯一的键。通常,这是通过尝试将ROWID 添加到查询中来完成的。这就是为什么,例如,Oracle JDBC 驱动程序指定一个可滚动或可更新的 ResultSet cannot use a SELECT *,但可以使用 SELECT alias.*——后者使得驱动程序有可能盲目地将 ROWID 列添加到查询。

然而,来自存储过程的 ResultSet 对驱动程序是完全不透明的——它无法获取用于打开 ResultSet 的查询,因此无法添加额外的键列或去返回并再次获取数据。如果驱动程序想要使 ResultSet 可滚动,则必须返回将整个 ResultSet 缓存在内存中。从技术上讲,这是完全可以做到的,但很少有司机会这样做,因为这往往会导致性能问题。降级 ResultSet 更安全。大多数时候,应用程序可以更好地判断缓存整个 ResultSet 是否合理,因为您知道它只会返回少量数据或能够返回并再次获取行用他们的自然键。

您可以在 ResultSet 上使用 getType()getConcurrency() 方法来确定您的 ResultSet 是否已被驱动程序降级。

【讨论】:

我对您链接中的 Oracle API 感到非常高兴。到目前为止,我在错误的地方寻找如此广泛的答案。但是,关于降级,getType()getConcurrency() 只允许我查询 ResultSet 属性。我对检查表明已执行此类降级的标志更感兴趣。那是因为我不确定我是否正确地为scrollable Resultset 指示JDBC。但是我认为可以从这里使用 oracle 的文档进行查询。维伦丹克

以上是关于从 Oracle DB 获取可滚动的结果集的主要内容,如果未能解决你的问题,请参考以下文章

使用可滚动结果集在休眠中批量读取数据

如何从 getMetaData.getColumns() 返回可滚动的结果集?

Jdbc进阶

Oracle查询从多维表中获取关系数据集结果

如何通过 JDBC 从 Db2 匿名块返回动态结果集?

从 Spring JAVA 中的 oracle PLSQL 函数获取结果集时出错