我有这张桌子:
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.通过OUT参数返回指向找到的记录的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;
调用此程序即可找到预订 并且字段已更新,但最后是光标 是无效的,我无法用于其他操作, 在这个例子中,我使用光标记录id字段
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-Booking
的形式检索更新的预订提前谢谢。
答案 0 :(得分:2)
引用游标不像我们在前端语言中找到的可滚动游标。它是指向结果集的指针。这意味着,我们可以阅读一次然后用尽。它不可重复使用。
“当选择预订时,我需要更新call_time以标记它 作为“已选择”。当预订具有非null时,call_time不可选 更多。我需要将更新的记录返回给java应用程序 所以我需要将它作为过程的第一个参数返回 OUT
sys_refcursor
类型。“请注意,真正的选择可能很难,所以我不想执行 它不止一次“
好的,这是一种方法。警告:这是概念证明(即未经测试的代码)并且不能保证可行,但它似乎是一个可行的解决方案。
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;
/
基本上:
您确实发出了两个查询,但选择使用ROWID非常快。
答案 1 :(得分:1)
问题在于(3) - '由OUT参数返回指向找到的记录的SYS_REFCURSOR'。它没有指向那个记录,因为你fetch
过去了。我假设你只是期待一个带有该ID的记录;如果您有多个,则返回的光标将指向具有该ID的 next 记录,但您的update
将更新具有该ID的所有匹配记录,而不仅仅是您获取的记录
如果您只有一条记录,为什么要使用光标?我能看到的唯一原因是允许您使用for update
,但您没有在更新中使用相应的where current of
。