什么返回带函数调用的CallableStatment.executeQuery()?

时间:2013-08-29 03:22:47

标签: java sql oracle jdbc plsql

假设有一些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没有数据,但结果有。这是正常的,但任何人都可以解释

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

2)当语句产生过程调用时,返回的ResultSet是否包含数据?或者它总是空的?

P.S.Possible optimization不是这个问题的目标。我希望按原样解释代码。

3 个答案:

答案 0 :(得分: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,但这个想法很清楚。

答案 1 :(得分:0)

  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不是一个类,而是JDBC开发人员的an interface to be implemented,在本例中是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)。

答案 2 :(得分: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参数(尽管最好这样做)。如您所见,不同的数据库可以通过不同的方式处理它。