从 pl/sql 异常块中“一次”关闭所有游标

Posted

技术标签:

【中文标题】从 pl/sql 异常块中“一次”关闭所有游标【英文标题】:Closing all cursors 'once' from a pl/sql exception block 【发布时间】:2011-11-03 16:28:35 【问题描述】:

有没有一种更简单的方法可以从 PL/SQL 程序 (Oracle 10G) 中关闭所有打开的游标。

我有一个可以产生许多异常的程序。要正确退出,我需要检查是否有 任何游标打开和关闭它们。这就是我最终遇到的情况。

Procedure test
is 
--
---
Begin
--
--
Exception
 when no_data_found then
    if cursorA%isopen close
    if cursorB%isopen close
    if cursorC%isopen close
 when invalid_date then
    if cursorA%isopen close
    if cursorB%isopen close
    if cursorC%isopen close
 when invalid_user then
    if cursorA%isopen close
    if cursorB%isopen close
    if cursorC%isopen close
 when others then
    if cursorA%isopen close
    if cursorB%isopen close
    if cursorC%isopen close 

End test;

显然,上述内容并不理想,尤其是在有许多例外条款的情况下。不是对每个异常块进行相同的检查,而是有一个 关闭所有打开光标的更快方法?注意:它只需要关闭当前运行的 pl/sql 程序打开的游标,因为可能还有其他的 pl/sql 程序也可以打开游标。

提前致谢

【问题讨论】:

不太熟悉 Oracle Exception 语法,但是您能否在测试您正在处理的异常类型之前将所有游标关闭语句? 否,因为当引发异常时,控制跳转到相关异常块的第一行。在某些情况下,我无法控制何时引发异常。 【参考方案1】:

您确定首先需要使用显式游标语法而不是使用隐式游标吗?如果您使用隐式游标,Oracle 会自动打开和关闭它们。您可以在下面的块中声明查询内联或外联

DECLARE
  CURSOR cursor_a
      IS SELECT *
           FROM emp;
BEGIN
  FOR a IN cursor_a
  LOOP
    <<do something>>
  END LOOP;

  FOR b IN (SELECT * 
              FROM dept)
  LOOP
    <<do something else>>
  END LOOP;
END;

在任何一种情况下,Oracle 都会在您退出块时自动关闭游标。

如果您出于某种原因确实需要使用显式游标,并假设您需要捕获多个不同的异常,因为您将以不同的方式处理这些异常,您可以创建一个嵌套块来关闭游标并从每个异常中调用它处理程序

DECLARE
  CURSOR cursor_a
      IS SELECT *
           FROM emp;
  CURSOR cursor_b
      IS SELECT *
           FROM dept;
  PROCEDURE close_open_cursors
  AS
  BEGIN
    IF( cursor_a%isopen )
    THEN
      close cursor_a;
    END IF;
    IF( cursor_b%isopen )
    THEN
      close cursor_b;
    END IF;
  END;
BEGIN
  OPEN cursor_a;
  OPEN cursor_b;
  RAISE no_data_found;
EXCEPTION
  WHEN no_data_found
  THEN
    close_open_cursors;
    <<do something meaningful>>
  WHEN too_many_rows
  THEN
    close_open_cursors;
    <<do something meaningful>>
  WHEN others
  THEN
    close_open_cursors;
    raise;
END;

【讨论】:

在某些情况下可能不会。我正在尝试更改现有代码,因此将所有显式游标更改为隐式需要时间。为了解决打开的游标问题,我想通过控制从一个地方关闭现有游标来最小化错误范围。 @ziggy - 发布了可以从每个异常处理程序调用以关闭所有游标的嵌套块的示例。这至少为您提供了一个放置所有清理逻辑的位置。 是的,应该可以。我想从现在开始最好的办法是避免使用显式游标。谢谢!

以上是关于从 pl/sql 异常块中“一次”关闭所有游标的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL 异常 ORA-06511 游标已打开

匿名 pl/sql 块中的声明顺序

为啥在匿名 PL/SQL 块中没有立即引发异常?

在 JDBC PL/SQL 块中多次使用命名参数时出错

PL/SQL基础知识结构

PL/SQL