当你不需要在oracle中关闭游标时?

时间:2015-02-04 20:32:27

标签: oracle

我正在使用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的正确方法是什么?

3 个答案:

答案 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)

来自documentation

  

在包中声明游标时(即不在   包的子程序)并且光标打开,它将保持打开状态   直到你明确关闭它或你的会话终止。

     

...   如果它是本地的,那么包括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声明。

分享并享受。