2

INパラメータを受け取り、 OUTカーソル パラメータを返すOracle PL/SQL プロシージャがあるとします。この手順を実行する 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 にデータが含まれることはありますか? それとも常に空ですか?

PS可能な最適化は、この質問の目標ではありません。コードをそのまま説明してほしい。

4

3 に答える 3

0

1)(JDBC仕様に準拠するために)ResultSetを作成しますが、データを照会することはできません(すでにわかっているようにデータが含まれていないため)。その上で 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);
    

    .executeQuery() ではなく .execute() を使用するふりをしていたようです。その場合、使用する方が理にかなっています

    ResultSet result = cstmt.getCursor(1);
    
  2. この線

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

    はプロシージャを生成しませんが、実際には parameters を使用するストアド プロシージャで構成されています。したがって、プロシージャを呼び出すと、データを取得する必要がある場合は常に ResultSet が出力されます。使用する場合

    secondaryResult.close();
    

    使用するふりをしていたデータで ResultSet を閉じます (ここでも、Oracle JDBC を使用している場合)。

于 2016-04-16T14:35:40.603 に答える