我正在用JDBC编写一个核心Java程序来连接到Oracle。
在两个选择中,我都使用相同的Statement对象。运行程序时,我仅获得第一行详细信息,然后Java抛出结果集关闭的错误
简而言之,我想知道是否可以在循环之前和循环内部使用单个Statement对象?
下面是我的代码示例
allCOBbatchRSet=stmt.executeQuery("SELECT RECID FROM V_F_BATCH WHERE BATCH_STAGE IS NOT NULL");
while (allCOBbatchRSet.next())
{
BatchRSet=stmt.executeQuery("SELECT XMLRECORD FROM F_BATCH WHERE RECID="+cobBatchRecId);
BatchRSet.next();
............
}
失败,例外
java.sql.SQLException: Closed Resultset: next at
oracle.jdbc.driver.InsensitiveScrollableResultSet.ensureOpen(InsensitiveScrollableResultSet.java:109) at
oracle.jdbc.driver.InsensitiveScrollableResultSet.next(InsensitiveScrollableResultSet.java:398) at
com.manohar.t24.COBDetails.getCOBDetails(COBDetails.java:46)
答案 0 :(得分:0)
在遍历由该语句创建的结果集时,您无法重用该语句,因为对该Statement
对象执行另一个查询(或任何其他语句类型)将自动关闭先前查询执行的结果集。这是JDBC API和规范所必需的。
如果要执行此操作,则需要禁用自动提交*并使用两个语句对象。
但是,您显示的代码是一种称为N + 1查询问题的反模式,通常,您不应循环遍历结果集以执行每行其他单独的选择:您可以创建一个执行该操作的单个select语句为了你。这通常会好很多。
例如,您可以使用:
select V_F_BATCH.RECID, F_BATCH.XMLRECORD
from V_F_BATCH
inner join F_BATCH
on F_BATCH.RECID = V_F_BATCH.RECID
where V_F_BATCH.BATCH_STAGE is not NULL
这还将避免您当前代码中可能出现的SQL注入问题。
*:禁用自动提交是必要的,因为JDBC要求任何语句执行都必须以自动提交模式提交。提交也将关闭打开的结果集,除非它们对提交而言是可保留的(尽管某些JDBC驱动程序对此宽松,并且结果集不会在自动提交边界上关闭)。