2012-02-15 1 views
1

でそれを再利用:は、OracleのストアドプロシージャでSYS_REFCURSORからデータを読み、私はこのテーブルを持っているのjava

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

それから私は、Oracleでの簡単なストアドプロシージャを持っています予約は と発見されたこのプロシージャを呼び出すと

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; 

:OUTパラメータで見つかったレコード 3.returns上2.update列見つかったレコードを指しSYS_REFCURSORフィールドが更新されますが、最後にカーソル が有効ではありませんし、私は私が使用してJavaで予約をモデル

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; 

idフィールドにログインするためにカーソルを使用して、この例では他の操作、 のためにそれを使用するカントれますエンティティ

@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 
} 

私のための唯一の要求はあります0 - 予約を選択し、同じトランザクションで同じトランザクションで更新してストアドプロシージャ - javaからストアドプロシージャを呼び出すと、@ Entity-Bookingの形式で更新された予約を取得します。

ありがとうございます。

+1

オブジェクトの作成時には引用符を使用しないでください。大文字と小文字を区別し、手間を省きます。 – Ben

答えて

2

refカーソルは、フロントエンド言語で見つかるスクロール可能カーソルと似ていません。結果セットへのポインタです。これは、一度それを読むことができ、それが疲れていることを意味します。再利用はできません。予約は、任意のより多くの。私は返す必要が 選択更新されない非ヌルcall_timeを持っている.When 『選択

は、「予約が選択されているときのように、私は それをマークするcall_timeを更新する必要があります』 javaアプリケーション にレコードので、私はOUT sys_refcursor型のプロシージャの最初のパラメータとしてそれを返す必要があります。

「私はより それ以上を実行する必要はありませんので、実際の選択は難しいかもしれないことに注意してください一度 "

さて、ここに1つのアプローチがあります。警告:これは概念の証明です(つまり、テストされていないコード)、動作することは保証されていませんが、実現可能なソリューションのようです。

​​

基本的には:あなたが更新された行

  • のROWIDをキャプチャするためにRETURNING句を使用し
  • を選択したい行(s)は、次にROWIDを使用して参照カーソルを開く

    1. 更新更新された行のみを選択します。

    2つのクエリを発行しますが、ROWIDを使用した選択は非常に高速です。

  • +0

    予約が選択されたとき、私はそれを "選択済み"としてマークするためにcall_timeを更新する必要があります。予約がnullでない場合、call_timeはこれ以上選択できません。 更新されたレコードをjavaアプリケーションに戻す必要があるので、OUT "sys_refcursor"タイプのプロシージャーの最初のパラメーターとして戻す必要があります。 (http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querysql.htmlを参照)。私は '選択して%rowtypeを使用してこれを行う方法があるかどうかわからないし、 "sys_refcursor"出力します。 – emmedierre

    1

    問題は、(3) - 'は、見つかったレコードを指すSYS_REFCURSORというOUTパラメータによって返されます。それはあなたがfetchを過ぎてしまったので、そのレコードを指していません。とにかくそのIDを持つ単一のレコードだけを期待していると仮定しています。複数ある場合、返されたカーソルはそのIDを持つ次のレコードを指しますが、updateは取り込んだレコードだけでなく、そのIDで一致するすべてのレコードを更新します。

    レコードが1つしかない場合は、なぜカーソルを使用しますか?私が見ることができる唯一の理由は、for updateを使用できるようにすることですが、アップデートに対応するwhere current ofを使用していません。

    +0

    @ user1210761 - レコードタイプを返すのが適切でない場合はOKです。しかし、同じカーソルをフェッチして返すことはできません。 'where current'を使用していないため、IDが一意でない場合は、複数の行を更新する可能性があります。あなたが持っているものを複数持っている場合は、あなたが持っているものを制御するために「注文する」必要があります。同じレコードを確実に得ることができれば、それをローカルカーソルで更新することができます。そして、2番目の同じ選択のために 'out'カーソルを開きますか? –

    +0

    私の質問の簡略化されたバージョンを投稿します。実際のバージョンには "... WHERE ROWNUM <= 1"という節がありますので、出力に1つの結果があります。プロシージャからレコード全体を取得し、それをJavaのBookingエンティティにバインドするにはsys_refcursorが必要です(hibernateのストアドプロシージャを使用するルールです:http://docs.jboss.org/hibernate/orm/3.3/reference/ en/html/querysql.html)。実際の選択は難しいので、複数回実行したくないことに注意してください(私はカーソルを再度開いて、再度選択を実行するようにしています) – emmedierre