【问题标题】:What returns CallableStatment.executeQuery() with function call?什么返回带有函数调用的 CallableStatment.executeQuery()?
【发布时间】:2013-09-01 08:19:22
【问题描述】:

假设有一些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可以包含数据吗?还是总是空的?

P.S.可能的优化不是这个问题的目标。我希望按原样解释代码。

【问题讨论】:

    标签: java sql oracle jdbc plsql


    【解决方案1】:

    您的语句在输出参数中获取结果。根据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 的,但是思路很清楚。

    【讨论】:

    • 见问题后记:“。可能的优化不是这个问题的目标。我希望代码按原样解释。”
    【解决方案2】:

    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 参数(尽管这样做更好)。如您所见,不同的数据库可以以不同的方式处理此问题。

    【讨论】:

      【解决方案3】:
      1. 既然你正在使用

        statement.registerOutParameter(1, OracleTypes.CURSOR);
        

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

        secondaryResult = statement.executeQuery();
        

        will return the ResultSet object generated by the query.

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

        import oracle.jdbc.OracleCallableStatement;
        

        从 OracleCallableStatement will be the inherited one from java.sql.PreparedStatement 调用 executeQuery 的行为。 CallableStatement 不是一个类,而是an interface to be implemented 由 JDBC 开发人员开发,在本例中是 Oracle。

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

        当你写作时

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

        好像你在假装use .execute() rather than .executeQuery(),那样的话用起来更有意义

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

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

        产生过程,而是actually composed of a stored procedure that uses parameters。因此,如果您应该从中获取数据,则调用该过程应始终输出 ResultSet。如果你使用

        secondaryResult.close();
        

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

      【讨论】:

      • 这是不正确的。如果存储过程/函数返回游标,则该游标应映射到 ResultSet。
      • @dsp_user 希望这个更正有意义。使用 oracle.jdbc.* 库应该自动将游标映射到结果集,请参阅我的答案的最后一行。
      • my own code为例。
      猜你喜欢
      • 2014-02-23
      • 2015-03-31
      • 2018-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      • 2012-05-06
      相关资源
      最近更新 更多