читать данные из SYS_REFCURSOR в хранимой процедуре Oracle и повторно использовать их в Java - PullRequest
1 голос
/ 15 февраля 2012

У меня есть эта таблица:

  CREATE TABLE "QMS_MODEL"."BOOKING" (
       "ID" NUMBER ( 19, 0 ) CONSTRAINT "QMS_BOOKING_NN_1" NOT NULL ENABLE
      ,"CALL_TIME" TIMESTAMP ( 6 )
  );

Затем у меня есть простая хранимая процедура в Oracle, которая: 1. получает запись из таблицы 2. обновляет столбец в найденной записи 3. возвращает наВыходной параметр SYS_REFCURSOR, который указывает на найденную запись:

CREATE OR REPLACE 
PROCEDURE GET_BOOKING
  ( 
    refCursorValue OUT SYS_REFCURSOR,
    bookingId IN QMS_MODEL.booking.id%type
  )
AS
    bookingResult QMS_MODEL.booking%ROWTYPE;
    todayAtNow QMS_MODEL.booking.booking_time%type;
BEGIN

  --********************************
  --get booking cursor....
  --********************************
  OPEN refCursorValue FOR 
  SELECT 
    bb.*
  FROM qms_model.booking bb 
  WHERE bb.id = bookingId 
  FOR UPDATE;


  --****************************************
  --from boking cursor get booking record...
  --****************************************
  FETCH refCursorValue INTO bookingResult;

  --********************************
  --update a column on found booking....
  --********************************
  SELECT SYSDATE into todayAtNow FROM DUAL;  
  UPDATE qms_model.booking SET 
          call_time = todayAtNow
  WHERE id = bookingResult.id;


  /*
  after the fetch refCursorValue is not
  valid and the client can't use it!
  */ 

END;

При вызове этой процедуры резервирование найдено, и поле обновлено, но в конце курсор недействителен, и я не могу использовать его для других операций.В этом примере я использую курсор для записи в поле идентификатора

set serveroutput on format wrapped;
DECLARE
  REFCURSORVALUE SYS_REFCURSOR;
  BOOKINGID NUMBER;
  bookingResult QMS_MODEL.booking%ROWTYPE;
BEGIN
  BOOKINGID := 184000000084539;
  GET_BOOKING(
    REFCURSORVALUE,
    BOOKINGID
  );
  FETCH REFCURSORVALUE INTO bookingResult;
  DBMS_OUTPUT.PUT_LINE('>>>OUT , cursor fetc,id='|| bookingResult.id ); 
END;

Я моделирую бронирование в Java, используя сущность

@Entity
@Table(name = "BOOKING", schema = "QMS_MODEL")
@NamedNativeQueries({    
    @NamedNativeQuery(name = "booking.callNext.Oracle",
    query = "call GET_BOOKING(?,:bookingId)",
    callable = true,
    resultClass = Booking.class)
})
public class Booking implements Serializable {
..
..
}

... и получаю его с помощью NamedNativeQuery:

long bookingID=...some value
Query q = entityMng.createNamedQuery("booking.callNext.Oracle");
q.setParameter("bookingId", bookingID);
List results = q.getResultList();
if (results!=null && !results.isEmpty()) {
  Booking eBooking = (Booking) results.get(0);
  ..
  ..
  ..
  ..i want use some booking data here....
  ..but i can't because the cursor is closed
}

единственный запрос для меня - выбрать бронирование и обновить его в той же транзакции в хранимой процедуре - вызвать хранимую процедуру из java и получить обновленное бронирование в форме @Entity-Бронирование

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 15 февраля 2012

Ссылочный курсор не похож на прокручиваемый курсор, который мы находим в языках интерфейса. Это указатель на набор результатов. Это означает, что мы можем прочитать его один раз, а затем он исчерпан. Это не для повторного использования.

"когда выбрано бронирование, мне нужно обновить call_time, чтобы отметить его как "выбранный". Когда бронирование имеет ненулевое значение, call_time не выбирается больше Мне нужно вернуть обновленную запись в приложение Java поэтому мне нужно вернуть его в качестве первого параметра процедуры с OUT sys_refcursor type.

"Обратите внимание, что реальный выбор может быть трудным, поэтому я не хочу выполнять это более одного раза "

Хорошо, вот один из подходов. Предостережение: это доказательство концепции (то есть непроверенный код), и оно не гарантировано работает, но кажется возможным решением.

CREATE OR REPLACE PROCEDURE GET_BOOKING  
 (      refCursorValue OUT SYS_REFCURSOR,     
        bookingId IN QMS_MODEL.booking.id%type   ) 
AS     
     rowids dbms_debug_vc2coll;
begin
     update  qms_model.booking bb  
     set     bb.call_time = sysdate
     where bb.id = bookingId 
     returning rowidtochar(rowid) bulk collect into rowids;

     open refCursorValue for
         select * 
         from qms_model.booking bbto
         where rowid in ( select chartorowid(column_value) from table(rowids));
end;
/

В основном:

  1. обновить строки, которые вы хотите выбрать
  2. использовать предложение RETURNING для захвата строк обновленных строк
  3. затем откройте рефкурсор, используя rowids, чтобы выбрать только обновленные строки.

Вы выдаете два запроса, но выбор с использованием ROWID выполняется довольно быстро.

1 голос
/ 15 февраля 2012

Проблема в (3) - «возвращает с помощью параметра OUT SYS_REFCURSOR, который указывает на найденную запись».Это не указывает на эту запись, потому что вы fetch прошли мимо нее.Я предполагаю, что вы ожидаете только одну запись с этим ID в любом случае;если у вас их больше одного, возвращаемый курсор будет указывать на запись next с этим идентификатором, но ваш update обновит все соответствующие записи с этим идентификатором, а не только те, которые вы выбрали.

Если у вас есть только одна запись, зачем использовать курсор?Единственная причина, которую я вижу, - позволить вам использовать for update, но вы не используете соответствующий where current of в обновлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...