sql >> データベース >  >> RDS >> Oracle

JDBCを使用してdbms_output.get_linesから出力を取得する

    この問題についてもここでブログに書いています。これを行う方法を示すスニペットを次に示します。

    try (CallableStatement call = c.prepareCall(
        "declare "
      + "  num integer := 1000;" // Adapt this as needed
      + "begin "
    
      // You have to enable buffering any server output that you may want to fetch
      + "  dbms_output.enable();"
    
      // This might as well be a call to third-party stored procedures, etc., whose
      // output you want to capture
      + "  dbms_output.put_line('abc');"
      + "  dbms_output.put_line('hello');"
      + "  dbms_output.put_line('so cool');"
    
      // This is again your call here to capture the output up until now.
      // The below fetching the PL/SQL TABLE type into a SQL cursor works with Oracle 12c.
      // In an 11g version, you'd need an auxiliary SQL TABLE type
      + "  dbms_output.get_lines(?, num);"
    
      // Don't forget this or the buffer will overflow eventually
      + "  dbms_output.disable();"
      + "end;"
    )) {
        call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
        call.execute();
    
        Array array = null;
        try {
            array = call.getArray(1);
            System.out.println(Arrays.asList((Object[]) array.getArray()));
        }
        finally {
            if (array != null)
                array.free();
        }
    }
    

    上記は印刷されます:

    [abc, hello, so cool, null]
    

    ENABLEに注意してください /DISABLE 設定は接続全体の設定であるため、複数のJDBCステートメントでこれを行うこともできます。

    try (Connection c = DriverManager.getConnection(url, properties);
         Statement s = c.createStatement()) {
    
        try {
            s.executeUpdate("begin dbms_output.enable(); end;");
            s.executeUpdate("begin dbms_output.put_line('abc'); end;");
            s.executeUpdate("begin dbms_output.put_line('hello'); end;");
            s.executeUpdate("begin dbms_output.put_line('so cool'); end;");
    
            try (CallableStatement call = c.prepareCall(
                "declare "
              + "  num integer := 1000;"
              + "begin "
              + "  dbms_output.get_lines(?, num);"
              + "end;"
            )) {
                call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
                call.execute();
    
                Array array = null;
                try {
                    array = call.getArray(1);
                    System.out.println(Arrays.asList((Object[]) array.getArray()));
                }
                finally {
                    if (array != null)
                        array.free();
                }
            }
        }
        finally {
            s.executeUpdate("begin dbms_output.disable(); end;");
        }
    }
    

    これにより、最大で1000行の固定サイズがフェッチされることにも注意してください。さらに行が必要な場合は、PL / SQLでループするか、データベースをポーリングする必要があります。

    DBMS_OUTPUT.GET_LINEの呼び出しに関する注意 代わりに

    以前は、DBMS_OUTPUT.GET_LINEへの個々の呼び出しを提案する削除された回答がありました 代わりに、一度に1行を返します。 DBMS_OUTPUT.GET_LINESと比較してアプローチのベンチマークを行いました 、およびその違いは大幅です。JDBCから呼び出すと最大30倍遅くなります(PL / SQLからプロシージャを呼び出すときにそれほど大きな違いはありませんが)。

    したがって、DBMS_OUTPUT.GET_LINESを使用した一括データ転送アプローチ 間違いなくそれだけの価値があります。ベンチマークへのリンクは次のとおりです。

    https://blog.jooq.org/2017/12/18/the-cost-of-jdbc-server-roundtrips/




    1. クラスでのPDOの使用

    2. Oracle CloudPlatformでのMySQLデータベースサービスでのOracleJDeveloperの使用、パート2

    3. MySQLでBLOBからTEXTに変換するにはどうすればよいですか?

    4. T-SQLで同等の分割関数?