62

这些信息应该很容易找到,但我没有任何运气。

当我BEGIN - END在 PL/SQL 中有一个块时,它是否表现为一个原子事务,它将尝试在命中该END块时提交,如果出现任何问题,则回滚更改?

如果不是,我如何确保 BEGIN - END 块内的代码表现得像一个原子事务,以及该块如何“默认”表现?

编辑:我认为我正在从存储过程运行并且我正在使用隐式块。

4

4 回答 4

75

首先,BEGIN..END只是句法元素,与事务无关。

其次,在 Oracle 中,所有单独的 DML 语句都是原子的(即它们要么完全成功,要么在第一次失败时回滚任何中间更改)(除非您使用 EXCEPTIONS INTO 选项,我不会在这里介绍)。

如果您希望将一组语句视为单个原子事务,您可以执行以下操作:

BEGIN
  SAVEPOINT start_tran;
  INSERT INTO .... ; -- first DML
  UPDATE .... ; -- second DML
  BEGIN ... END; -- some other work
  UPDATE .... ; -- final DML
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK TO start_tran;
    RAISE;
END;

这样,任何异常都会导致该块中的语句回滚,但在该块之前运行的任何语句都不会回滚。

请注意,我不包含 COMMIT - 通常我更喜欢调用进程来发出提交。


确实,没有异常处理程序的 BEGIN..END 块会自动为您处理:

BEGIN
  INSERT INTO .... ; -- first DML
  UPDATE .... ; -- second DML
  BEGIN ... END; -- some other work
  UPDATE .... ; -- final DML
END;

如果引发异常,所有的插入和更新都将回滚;但是只要你想添加一个异常处理程序,它就不会回滚。所以我更喜欢使用保存点的显式方法。

于 2012-08-16T02:00:22.530 回答
8

BEGIN-END块是 PL/SQL 的构建块,每个 PL/SQL 单元都包含在至少一个这样的块中。嵌套——PL BEGIN/ ENDSQL 块中的块通常用于捕获某些异常并处理该特殊异常,然后引发不相关的异常。然而,在 PL/SQL 中,您(客户端)必须始终为事务发出提交或回滚。

如果您希望在包含事务的 PL/SQL 中具有原子事务,则需要PRAGMA AUTONOMOUS_TRANSACTION在声明块中声明 a。这将确保该块中的任何 DML 都可以独立于包含的事务提交或回滚。

但是,您不能为嵌套块声明此编译指示。您只能为:

  • 顶级(非嵌套)匿名 PL/SQL 块
  • 项目清单
  • 本地、独立和打包的函数和过程
  • SQL 对象类型的方法
  • 数据库触发器

参考:甲骨文

于 2012-08-15T18:38:25.063 回答
1

你没有提到这是一个匿名的 PL/SQL 块还是一个声明性的,即。包、过程或功能。但是,在 PL/SQL 中,必须显式提交 COMMIT 以将事务保存到数据库。COMMIT 实际上将所有未保存的事务从您当前用户的session保存到数据库。

如果发生错误,事务会隐式执行 ROLLBACK。

这是 PL/SQL 的默认行为。

于 2012-08-15T08:29:26.647 回答
0

Commit PL/SQL 块的默认行为:

您应该明确提交或回滚每个事务。是在 PL/SQL 程序中还是从客户端程序中发出提交或回滚取决于应用程序逻辑。如果您没有明确提交或回滚事务,客户端环境将确定其最终状态。

例如,在 SQL Plus 环境中,如果您的 PL/SQL 块不包含 COMMIT 或 ROLLBACK 语句,则事务的最终状态取决于您在运行该块后所做的事情。如果执行数据定义、数据控制或 COMMIT 语句,或者发出 EXIT、DISCONNECT 或 QUIT 命令,Oracle 将提交事务。如果执行 ROLLBACK 语句或中止 SQL Plus 会话,Oracle 会回滚事务。

https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/sqloperations.htm#i7105

于 2020-09-29T09:19:23.213 回答