问题描述
我们有针对 Oracle 根容器 ResultSet
中的视图打开 cdb$root
的代码。虽然代码迭代行,但有一个用例需要执行特定的函数调用,但此调用必须在特定可插入数据库的上下文中进行,在我们的示例中为 ORCLDPB1
。实际上,代码如下所示:
while (resultSet.next()) {
LOGGER.info("ResultSet Closed (Top Of Loop): {}",resultSet.isClosed());
if (someSpecialUseCaseIsTrue) {
try (Statement s = connection.createStatement()) {
LOGGER.info("ResultSet Closed (Creating new statement): {}",resultSet.isClosed());
try {
s.executeUpdate("ALTER SESSION SET CONTAINER=ORCLPDB1");
LOGGER.info("ResultSet Closed (after alter session): {}",resultSet.isClosed());
// perform some PDB specific operation
}
finally {
s.executeUpdate("ALTER SESSION SET CONTAINER=cdb$root");
LOGGER.info("ResultSet Closed (after alter back to root): {}",resultSet.isClosed());
}
}
}
}
输出为:
ResultSet Closed (Top Of Loop): false
ResultSet Closed (Creating new statement): false
ResultSet Closed (after alter session): true
ResultSet Closed (after alter back to root): true
然后当 while 在第二次迭代时检查 resultSet.next()
这会产生
java.sql.sqlException: Closed Resultset: next
at oracle.jdbc.driver.InsensitiveScrollableResultSet.ensureOpen(InsensitiveScrollableResultSet.java:133)
at oracle.jdbc.driver.InsensitiveScrollableResultSet.next(InsensitiveScrollableResultSet.java:428)
通过调试,我确定外部 ResultSet
保持打开状态,直到 ALTER SESSION
被执行,然后立即调用 isClosed()
返回外部结果集不再是打开。
这种行为是由于在现有 ResultSet
处于打开状态时执行另一个操作,还是因为正在执行的实际语句,即 ALTER SESSION
?如果是后者,为什么这会强制 ResultSet
无效?
解决方法
来自Oracle "Administering a CDB with SQL*Plus" documentation:
40.2.3 使用 ALTER SESSION 语句切换到容器
...
以下是使用 ALTER SESSION SET CONTAINER
语句的注意事项:
- ...
- 如果您打开一个游标并使用
ALTER SESSION SET CONTAINER
切换到不同的容器,则您无法从该游标中获取数据,除非您切换回打开该游标的容器。