Oracle
 sql >> база данни >  >> RDS >> Oracle

Получаване на изход от dbms_output.get_lines с помощта на JDBC

Аз също писах в блог за този проблем тук. Ето фрагмент, който илюстрира как може да се направи това:

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 вместо това, което връща един ред в даден момент. Направих сравнителен анализ на подхода, сравнявайки го с DBMS_OUTPUT.GET_LINES , а разликите са драстични – до 30 пъти по-бавно при извикване от JDBC (дори и да няма голяма разлика при извикване на процедурите от PL/SQL).

И така, подходът за групово прехвърляне на данни с помощта на DBMS_OUTPUT.GET_LINES определено си заслужава. Ето линк към бенчмарка:

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




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle Apex 5.0 – Показване на статично изображение

  2. SEC_CASE_SENSTIVE_LOGON в 12c

  3. Oracle намери ограничение

  4. Функция ABS() в Oracle

  5. Оптимизиране на SELECT заявка, която работи бавно на Oracle, която се изпълнява бързо на SQL Server