2012-08-15 27 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