2

假设有一些 Oracle PL/SQL 过程,它接收IN参数并返回OUT游标参数。我有一个执行此过程的 jdbc 代码:

DataSource dataSource;
    //datasource was set
    CallableStatement statement = null;
    ResultSet result = null;
    ResultSet secondaryResult = null;
    Connection connection = null;
    try {
        connection = dataSource.getConnection();
        statement = connection.prepareCall("{? = call pl_sql_func(?)}");
        statement.registerOutParameter(1, OracleTypes.CURSOR);
        statement.setString(2,"param");
        // !
        secondaryResult = statement.executeQuery();
        secondaryResult.close();

        result = (ResultSet) statement.getObject(1);

        while(result.next()){
            //get some data
        }

    } catch (Exception ex){

    }

    finally{
        //closing statement, result, secondaryResult and connection
    }

我尝试执行这段代码,发现 secondaryResult 没有数据,但 result 有。很正常,但是谁能解释

1)statement.executeQuery()真正产生什么?

2) 当语句产生过程调用时,返回的ResultSet 可以包含数据吗?还是总是空的?

PSPossible 优化不是这个问题的目标。我希望按原样解释代码。

4

3 回答 3

0

您的语句在输出参数中获取结果。根据 Oracle 教程http://docs.oracle.com/javase/tutorial/jdbc/basics/storedprocedures.html#create_jdbc_mysql这是如何将 ResultSet 作为 CallableStatement.executeQuery 返回值

statement = connection.prepareCall("{call pl_sql_func(?)}");

这个例子是针对 MySQL 的,但是思路很清楚。

于 2013-08-29T04:53:33.277 回答
0

1)虽然它确实创建了一个 ResultSet(以符合 JDBC 规范),但不能查询它的数据(因为它不包含您已经知道的数据)。如果您在其上执行 ResultSet.next(),您将收到“无法对 Pl/SQL 语句执行提取”错误。

2)在Oracle上它总是空的(至少在我使用的驱动程序上)。例如,在 PostgreSQL 上,可以从这个 ResultSet 中获取数据。实际上,您会从第一个 ResultSet 中获得另一个基于游标的结果集。

 //PostgreSQL
          ResultSet rs=null;
          CallableStatement stmt=null;
          String sqlQuery = "{ call pl_sql_func(?)}";//no out param needed here
          stmt=conn.prepareCall(sqlQuery);      

          stmt.setString(1, "param");//just 1 input param

          ResultSet rss =null;
          rss = stmt.executeQuery(); 

          if(rss!=null&&rss.next()){
              rs = (ResultSet)rss.getObject(1);
              rss.close();
          }

          while(rs.next()){
                //get data here
          }

请注意,在 PostgreSQL 中,您甚至不必使用 RegisterOutParameter 指定 OUT 参数(尽管这样做更好)。如您所见,不同的数据库可以以不同的方式处理此问题。

于 2016-04-16T19:50:24.083 回答
0
  1. 由于您正在使用

    statement.registerOutParameter(1, OracleTypes.CURSOR);
    

    我可以安全地假设您的数据库 SQL 过程不应该返回游标,而是调用

    secondaryResult = statement.executeQuery();
    

    将返回查询生成的 ResultSet 对象

    如果您要导入 Oracle 的 ODBC 驱动程序(而不是通用 Java 驱动程序),请使用:

    import oracle.jdbc.OracleCallableStatement;
    

    从 OracleCallableStatement 调用 executeQuery 的行为将继承自 java.sql.PreparedStatement。CallableStatement 不是一个类,而是由 JDBC 开发人员(在本例中为 Oracle)实现的接口。

    (PS .:您应该改为使用 OracleCallableStatement。

    当你写

    result = (ResultSet) statement.getObject(1);
    

    似乎您假装使用 .execute() 而不是 .executeQuery(),在这种情况下使用更有意义

    ResultSet result = cstmt.getCursor(1);
    
  2. 线

    statement = connection.prepareCall("{? = call pl_sql_func(?)}");
    

    产生过程,但实际上使用参数的存储过程组成。因此,如果您应该从中获取数据,则调用该过程应始终输出 ResultSet。如果你使用

    secondaryResult.close();
    

    您将使用您假装使用的数据关闭 ResultSet(同样,如果您使用的是 Oracle JDBC)。

于 2016-04-16T14:35:40.603 回答