从SYS_REFCURSOR在Oracle存储过程中读取数据,并在Java
重用我有这个表:从SYS_REFCURSOR在Oracle存储过程中读取数据,并在Java
CREATE TABLE "QMS_MODEL"."BOOKING" (
"ID" NUMBER (19, 0) CONSTRAINT "QMS_BOOKING_NN_1" NOT NULL ENABLE
,"CALL_TIME" TIMESTAMP (6)
);
然后,我在Oracle中,一个简单的存储过程: 1.get记录从表中 通过OUT参数2.更新上找到的记录 3.returns一列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的形式检索更新的预订
预先感谢您。
引用游标不像我们在前端语言中找到的可滚动游标。它是一个指向结果集的指针。这意味着,我们可以阅读一次,然后用尽。它不可重用。
“当选择了预约我需要更新call_time将其标记为 ‘选择’。当预订有一个非空call_time不可选 了。我需要返回更新记录Java应用程序 ,所以我需要把它作为返回程序的第一参数 OUT
sys_refcursor
类型。“需要注意的是真正的选择可能会很辛苦,所以我不希望执行 它不止一次“
好的,这是一种方法。警告:这是概念验证(即未经测试的代码),并不保证能够正常工作,但它似乎是一种可行的解决方案。
基本上是:
- 更新的行(或多个)要选择
- 使用returning子句来捕捉更新的行
- 的的rowid然后使用的rowid打开REFCURSOR只选择更新的行。
您确实发出了两个查询,但使用ROWID选择的速度相当快。
当预订被选中时,我需要更新call_time以将其标记为“已选择”。当预订有非空call_time时,不再可选。 我需要将更新后的记录返回给java应用程序,所以我需要将它作为OUT“sys_refcursor”类型的过程的第一个参数返回。 (参见http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querysql.html)。我不知道是否有一种方法可以在select中使用%rowtype,然后在输出中使用“sys_refcursor”。 – emmedierre 2012-02-15 13:35:28
问题出在(3) - '通过OUT参数返回一个SYS_REFCURSOR指向找到的记录'。它没有指向那条记录,因为你已经通过了fetch
。我假设你只用一个ID就可以得到一个记录;如果您有多个,则返回的光标将指向具有该ID的下一个记录,但您的update
将更新具有该ID的所有匹配记录,而不仅仅是您获取的记录。
如果您只有一条记录,为什么要使用游标?我能看到的唯一原因是允许您使用for update
,但是您没有在更新中使用相应的where current of
。
@ user1210761 - 好的,如果返回记录类型不可行。但是你仍然无法获取并返回相同的游标;如果ID不是唯一的,你仍然可能会更新多行,因为你没有使用'where current of';如果你确实有不止一个,你需要一个'order by'来控制你得到的。如果你可以可靠地获得相同的记录,你可以在本地光标中更新它,然后打开“out”光标进行第二个相同的选择? – 2012-02-15 13:30:15
我发布了我的查询的简化版本,在真实版本中有一个子句“... WHERE ROWNUM emmedierre 2012-02-15 13:45:23
请在创建对象时不要使用引号。它使得它们区分大小写,并且不会引起麻烦。 – Ben 2012-02-15 11:44:58