2012-08-15 46 views
44

该信息应该很容易找到,但我没有任何运气。BEGIN - END PL/SQL中的块原子事务

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

如果不是,我该如何确保BEGIN-END块内的代码的行为类似于原子事务,并且该块如何在默认情况下运行?

编辑:我从一个存储过程运行,我使用一个隐式块,我想。

+0

如果这是你正在寻找的行为,你应该发出显式的'COMMIT'和'ROLLBACK'语句(可能在'EXCEPTION'部分)。如果您确实需要一个原子事务,请查看Oracle中的AUTONOMOUS_TRANSACTIONS。 – Ollie 2012-08-15 08:27:52

回答

57

首先,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; 

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

+0

如果在异常处理中使用嵌套块但在主/外部块中没有异常处理,它是一个事务吗? – 2013-12-02 12:43:28

+0

@JonnyLeeds,不,当你开始运行DML语句时,它是一个事务。 – 2013-12-02 22:30:49

0

你不会提及这是一个匿名PL/SQL块还是一个声明式块,包,程序或功能。 但是,在PL/SQL中必须显式执行COMMIT以将事务保存到数据库。 COMMIT实际上将所有未保存的交易从当前用户的会话保存到数据库。

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

这是PL/SQL的默认行为。

+1

我不确定说* transaction是否回滚是正确的;在PL/SQL块之前所做的任何未提交的更改仍然未决,并且需要由客户端提交或回滚。在块中采取的任何操作都将回滚,就好像保存点一样,我认为这是您的意思。 (像往常一样,[汤姆解释得比我好](http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:43818437682131))。我也不确定OP是否询问块内的嵌套块,以及内部块中的更改是否将独立提交/回滚。 – 2012-08-15 14:46:45

5

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

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

但是,您不能为嵌套块声明此附注。您只能声明此为:

  • 顶级(未嵌套)匿名PL/SQL块
  • 列表项
  • 本地的,独立的,并打包的函数和过程
  • 一个SQL对象的
  • 方法键入
  • 数据库触发器

参考:Oracle