我正在使用TOAD在Oracle 10.2中工作。
我有一个类似的脚本:
DECLARE
my_query VARCHAR2(500) := 'select C1, C2, C3 FROM MYSCHEMA.MYTABLE';
TYPE my_record_type IS RECORD
(
C1 MYTABLE.C1%TYPE,
C2 MYTABLE.C2%TYPE,
C3 MYTABLE.C3%TYPE
);
TYPE my_table_type IS TABLE OF my_record_type;
my_records my_table_type;
my_cursor SYS_REFCURSOR;
BEGIN
OPEN my_cursor FOR my_records;
FETCH my_cursor
BULK COLLECT INTO my_records
LIMIT 1000;
FOR indx IN 1 .. my_records.COUNT
LOOP
/* SOME CODE HERE*/
IF /* CONDITION */ THEN
EXIT;
END IF;
END LOOP;
CLOSE my_cursor;
END;
我已经读过,如果你CLOSE一个已经关闭的游标,oracle会引发INVALID_CURSOR异常。
我还读过,当你在FOR LOOP中使用CURSOR时,oracle会在LOOP结束时显式关闭游标。所以理论上我不需要像我一样关闭光标,我应该得到一个例外,我不是。
现在我需要在LOOP中添加一个条件,它将导致它退出LOOP。 我读到oracle在FOR LOOP中使用EXIT或抛出EXCEPTION时会隐式关闭CURSORS。
那么我应该明确关闭CURSOR吗?如果我这样做,并且CURSOR因为我调用EXIT而关闭,它应该抛出异常吗?
如果我删除关闭光标的显式调用,是否会出现内存泄漏?
在这种情况下使用CURSOR的正确方法是什么?
答案 0 :(得分:6)
似乎你在for循环中使用游标for循环混淆游标。前者就是你所说明的。后者看起来像这样:
DECLARE
cursor my_cursor is select C1, C2, C3 FROM MYSCHEMA.MYTABLE;
BEGIN
FOR my_record in my_cursor LOOP
/* SOME CODE HERE*/
IF /* CONDITION */ THEN
EXIT;
END IF;
END LOOP;
CLOSE my_cursor;
END;
在这种情况下,close
语句将抛出一个错误,因为游标是由for
语句隐式打开的,并且在循环结束时隐式关闭。
总而言之,如果您有open
语句,则还应该有close
语句。如果您隐式打开游标,则可以相信它将被隐式关闭。
答案 1 :(得分:1)
在包中声明游标时(即不在 包的子程序)并且光标打开,它将保持打开状态 直到你明确关闭它或你的会话终止。
... 如果它是本地的,那么包括CLOSE声明也会向其他>开发者和您的经理表明您正在关注。
所以我认为你关闭它是因为你被告知并且如果你打算将你的代码迁移到一个包中它是一个好主意。
答案 2 :(得分:1)
这是一个简单的规则 - 如果您必须编写OPEN
语句来打开游标,则必须编写匹配的CLOSE
语句来关闭游标。
因此,如果你有
DECLARE
CURSOR some_cursor IS SELECT * FROM SOME_TABLE;
some_table_row SOME_TABLE%ROWTYPE;
BEGIN
OPEN some_cursor;
LOOP
FETCH some_cursor INTO some_table_row;
EXIT WHEN some_cursor%NOTFOUND; -- this exit **WILL NOT** close some_cursor
END LOOP;
然后在你的代码中的某个时候你必须有
CLOSE some_cursor;
END;
如果使用游标FOR循环打开光标,例如
BEGIN
FOR aRow IN some_cursor LOOP
-- whatever
IF aRow.SOME_THING = 'xyz' THEN
EXIT; -- this EXIT **will** close the cursor
END IF;
END LOOP;
或者您甚至没有明确的游标声明:
FOR aRow IN (SELECT * FROM SOME_TABLE) LOOP
-- blah, blah
IF aRow.YADA_YADA = 'BADA BOOM!' THEN
EXIT; -- this EXIT **will** close the cursor
END IF;
END LOOP;
然后您不需要或想要撰写CLOSE
声明。
分享并享受。