Выполнить блок PL / SQL в Oracle 11g и обработать курсор в клиенте Java - PullRequest
0 голосов
/ 12 декабря 2018

Мы пытаемся реализовать решение, которое требует от нас,

  1. Частый опрос контрольной таблицы для запроса необработанных транзакций

  2. Как только мы извлекаем идентификаторы транзакций из шага 1, мы должны запросить детали.Этот шаг является существующей функциональностью, только мы выполняем полное сканирование, объединяя его с контрольной таблицей на первом шаге.

Существующее решение начинает замедлять обработку при наличии тома.Поэтому мы решили извлечь транзакции, которые не были обработаны, из таблицы состояния и выполнить поиск PK для запроса деталей.

Я понимаю, что это не идеальное решение, такое как адаптеры, CDC или полное представление деталей в виде.Мы ограничены из-за контракта на продукт, который запрещает нам создавать объекты любого типа в исходной схеме или в любом месте исходного экземпляра Oracle, что оставляет нам опрос таблиц, и это решение должно быть масштабируемым и практически в реальном времени (задержка 5 секунд).

DDL:

 CREATE TABLE "CONTROL_TABLE"
(   
"REF_NO" VARCHAR2(16 CHAR), 
"BRANCH" VARCHAR2(3 CHAR),
"INIT_DATE" DATE, 
"STATUS" VARCHAR2(1 CHAR), 
 CONSTRAINT "CONST_CONTROL_TABLE" PRIMARY KEY ("REF_NO")
)

Ниже приведено то, что я пробовал в качестве POC, выполняя приведенный ниже блок,
1. Создал блок для запуска SELECT для UPDATE следующим образом.В приведенном ниже блоке я выбираю для обновления «SKIP LOCKED» и обновлять записи в области видимости курсора.

 DECLARE
   CURSOR tCURSOR IS
     SELECT REF_NO FROM CONTROL_TABLE 
        WHERE STATUS = 'U' FOR UPDATE OF STATUS SKIP LOCKED;
 BEGIN
  FOR tCURSORREC IN tCURSOR LOOP
    UPDATE CONTROL_TABLE SET STATUS='W' WHERE STATUS='U';    
  END LOOP; 
  COMMIT;  
 END;  

Приведенный выше блок работает просто отлично, и я проверил, вставив новые записи случайным образом и обновив статус из разных сеансов клиента.Моя проблема в том, что я хотел бы вернуть курсор клиенту Java для последующей обработки.Обратился к предыдущему посту, где только запрос SELECT возвращает Java привязки курсора.Любой полезный указатель высоко ценится. Выполнить анонимный блок pl / sql и получить набор результатов в java

Фрагмент Java, который запускает блок,

    public static void main(String args[]) throws Exception
    {
       final Connection c = DriverManager.getConnection("jdbc:oracle:thin:<<service_name>>:8888:<<schema>>", "user", "passwd");

     String plsql = "declare\r\n" + 
            "  cursor tCursor is\r\n" + 
            "    select ref_no from CONTROL_TABLE \r\n" + 
            "        where status = 'U' for update of REF_NO,STATUS skip locked;\r\n" + 
            "begin\r\n" +        
            "  for tCursorRec in tCursor loop\r\n" + 
            "    update CONTROL_TABLE set status='W' where status ='U';    \r\n" + 
            "  end loop;\r\n" +             
            "  commit;  \r\n" + 
            "? := tCursor" +
            "end;";     

            CallableStatement cs = c.prepareCall(plsql);
            cs.registerOutParameter(1, OracleTypes.CURSOR);
            cs.execute();          

            ResultSet cursorResultSet = (ResultSet) cs.getObject(1);
            while (cursorResultSet.next ())
            {
               System.out.println (cursorResultSet.getString(1));
            } 
                cs.close();
                c.close();

   Exception:Exception in thread "main" java.sql.SQLException: ORA-06550: 
   line 10, column 8:
   PLS-00382: expression is of wrong type
   ORA-06550: line 10, column 1:

1 Ответ

0 голосов
/ 12 декабря 2018

Использование ref-курсора проблематично, потому что вы исчерпали существующий PL / SQL-курсор (который в любом случае не совпадает с типом ref-курсора, следовательно, ошибка), и вы не можете запросить, поскольку вы ужеобновил и передал изменения.На самом деле фиксация, вероятно, должна выполняться со стороны Java, но это отдельная проблема.

Вместо этого можно использовать коллекцию, например, используя встроенный varray тип :

    Connection c = ods.getConnection();

    String plsql = "declare\r\n" +
        "  cursor tCursor is\r\n" +
        "    select ref_no from CONTROL_TABLE\r\n" +
        "        where status = 'U' for update of STATUS skip locked;\r\n" +
        "  array SYS.ODCIVARCHAR2LIST := new SYS.ODCIVARCHAR2LIST();\r\n" +
        "begin\r\n" +
        "  for tCursorRec in tCursor loop\r\n" +
        "    update CONTROL_TABLE set status='W' where current of tCURSOR;\r\n" +
        "    array.extend();\r\n" +
        "    array(array.count) := tCURSORREC.REF_NO;\r\n" +
        "  end loop;\r\n" +
        "  commit;\r\n" +
        "  ? := array;\r\n" +
        "end;";

    CallableStatement cs = c.prepareCall(plsql);
    cs.registerOutParameter(1, java.sql.Types.ARRAY, "SYS.ODCIVARCHAR2LIST");
    cs.execute();

    String[] refNos = (String[]) cs.getArray(1).getArray();

    cs.close();
    c.close();

    for (String refNo : refNos)
    {
        // Whatever processing you want to do
        System.out.println(refNo);
    }

Сгенерированный блок PL / SQL заканчивается как:

declare
  cursor tCursor is
    select ref_no from CONTROL_TABLE
        where status = 'U' for update of STATUS skip locked;
  array SYS.ODCIVARCHAR2LIST := new SYS.ODCIVARCHAR2LIST();
begin
  for tCursorRec in tCursor loop
    update CONTROL_TABLE set status='W' where current of tCURSOR;
    array.extend();
    array(array.count) := tCURSORREC.REF_NO;
  end loop;
  commit;
  ? := array;
end;

Внутри цикла курсора коллекция array расширяется (поэтому в конце у нее есть пустой элемент)и ref_no для этой строки курсора добавляется в массив в этой позиции.

Я также изменил обновление, чтобы оно применялось только к одной строке за раз, используя where current of - что предназначено длястрока заблокирована for update.В своей первоначальной версии вы выполняли неограниченное обновление всех строк с помощью буквы «U»;не только те, которые вы заблокировали, и поскольку все они обновлены в первом раунде timr, последующим итерациям цикла не осталось ничего для обновления.

На стороне Java переменная bind являетсятоже массив, и это можно привести к локальному массиву соответствующего типа.

Вы можете избежать явного курсора с помощью чего-то вроде:

begin
  update CONTROL_TABLE set status='W' where status = 'U'
  returning REF_NO
  bulk collect into ?;
  commit;
end;
/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...