PL / SQL 101:定義和管理事務
如果您有一個只讀資料庫,則不必擔心事務。但是對於你將要構建的幾乎所有應用程式,情況並非如此。因此,交易的概念和管理對於您的應用程式的成功至關重要。
事務是Oracle資料庫作為一個單元處理的一個或多個SQL語句的序列:要麼執行所有語句,要麼都不執行。事務隱含地從獲取TX鎖的任何操作開始:
- 發出修改資料的語句(例如,插入,更新,刪除,合併)
- 發出SELECT ... FOR UPDATE語句時
- 使用SET TRANSACTION語句或DBMS_TRANSACTION包顯式啟動事務時
發出COMMIT或ROLLBACK語句會明確結束當前事務。
本文將介紹如何使用以下語句和功能定義,管理和控制應用程式中的事務:
- 提交和回滾
- 儲存點
- 自治交易
- SET TRANSACTION語句
您可以在下面的事務處理和控制(doc)以及Oracle Live SQL和Oracle Dev Gym資源的連結中找到更多詳細資訊。
提交和回滾
回想一下事務的定義:“事務是Oracle資料庫作為一個單元處理的一個或多個SQL語句的序列:要麼執行所有語句,要麼都不執行。” 當所有語句都“執行”時,這意味著您已將它們提交或儲存到資料庫中。
使用COMMIT語句儲存所有更改,並使其對其他使用者可見。請記住:在提交之前,沒有人能夠看到特定會話中所做的更改。提交後,每個有權訪問受影響表的使用者現在都可以看到表的新“狀態”。
使用ROLLBACK語句撤消自上次提交以來(或自您在會話中啟動第一個事務以來)的所有更改。
此LiveSQL教程(Oracle Dev Gym上的開發人員資料庫課程的一部分)演示了事務管理的這些基本元素。
可是等等!如果您只想撤消會話中的某些更改,但保留其他更改,準備在將來的某個時間點提交,該怎麼辦?歡迎來到儲存點世界。
儲存點
儲存點允許您回滾部分事務而不是整個事務。每個會話的活動儲存點數量不受限制。
回滾到儲存點時,標記在該儲存點之後的任何儲存點都將被刪除。回滾的儲存點不會被刪除。簡單的回滾或提交會擦除所有儲存點。
儲存點名稱是未宣告的識別符號。在事務中重用儲存點名稱會將儲存點從其舊位置移動到事務中的當前點,這意味著回滾到儲存點僅影響事務的當前部分。
對於我們之間的遞迴程式設計師:如果在遞迴子程式中標記儲存點,則SAVEPOINT語句的新例項在遞迴下降的每個級別執行,但是您只能回滾到最近標記的儲存點。
以下是使用儲存點的示例(從同一個LiveSQL教程中提取):
CREATE TABLE toys ( toy_id INTEGER, toy_name VARCHAR2 (100), colour VARCHAR2 (10) ) / DECLARE l_count INTEGER; BEGIN INSERT INTO toys (toy_id, toy_name, colour) VALUES (8, 'Pink Rabbit', 'pink'); SAVEPOINT after_six; INSERT INTO toys (toy_id, toy_name, colour) VALUES (9, 'Purple Ninja', 'purple'); SELECT COUNT (*) INTO l_count FROM toys WHERE toy_id IN (8, 9); DBMS_OUTPUT.put_line (l_count); ROLLBACK TO SAVEPOINT after_six; SELECT COUNT (*) INTO l_count FROM toys WHERE toy_id IN (8, 9); DBMS_OUTPUT.put_line (l_count); ROLLBACK; SELECT COUNT (*) INTO l_count FROM toys WHERE toy_id IN (8, 9); DBMS_OUTPUT.put_line (l_count); END; / 2 10
自治交易
預設情況下,執行COMMIT語句時,會儲存會話中所有未儲存的更改。當您回滾時,所有未儲存的更改都將被刪除。
但有時候,我們只想儲存其中一個更改,而不儲存其他更改。此方案的最典型用例是錯誤日誌記錄。我想將資訊寫入我的錯誤日誌表並儲存,但後來我需要回滾事務(畢竟,有一個錯誤)。
我可以使用儲存點來執行此操作(請參閱上一節),但是當您呼叫可重用的日誌記錄程式時,很難一致且可靠。幸運的是,我可以簡單地使我的錯誤記錄過程成為一個自治事務。然後,我可以插入錯誤資訊並提交該插入,而不會影響業務事務,隨後將回滾該業務事務。
它很容易做到!
只需將此語句新增到過程或函式的宣告部分......
PRAGMA AUTONOMOUS_TRANSACTION;
然後適用以下規則:
在關閉子程式並將控制權傳遞迴呼叫塊之前,必須提交或回滾在該子程式中進行的任何DML更改。
如果有任何未儲存的更改,PL / SQL引擎將引發ORA-06519異常,如下所示:
CREATE OR REPLACE FUNCTION nothing RETURN INTEGER IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN UPDATE employees SET last_name = 'abc'; RETURN 1; END; / BEGIN DBMS_OUTPUT.put_line (nothing); END; / ORA-06519: active autonomous transaction detected and rolled back ORA-06512: at "STEVEN.NOTHING", line 10 ORA-06512: at line 2
以下是在錯誤記錄過程中使用此功能的示例:
CREATE OR REPLACE PACKAGE BODY error_mgr IS PROCEDURE log_error (app_info_in IN VARCHAR2) IS PRAGMA AUTONOMOUS_TRANSACTION; c_code CONSTANT INTEGER := SQLCODE; BEGIN INSERT INTO error_log (created_on, created_by, errorcode, callstack, errorstack, backtrace, error_info) VALUES (SYSTIMESTAMP, USER, c_code, DBMS_UTILITY.format_call_stack, DBMS_UTILITY.format_error_stack, DBMS_UTILITY.format_error_backtrace, app_info_in); COMMIT; END; END;
此LiveSQL指令碼包含完整(和非常基本)的錯誤記錄包。
此LiveSQL指令碼演示了自治事務編譯指示的效果。
SET TRANSACTION語句
使用SET TRANSACTION語句將當前事務建立為只讀或讀/寫,建立其隔離級別,將其分配給指定的回滾段,或為事務指定名稱。
當您將事務設定為只讀時,查詢將返回事務開始時存在的資料,並且 您只能執行select語句。以下是使用此選項的示例,該選項來自Chris Saxon出色的LiveSQL模組:
set transaction read only; select * from toys; update toys set price = price + 1; declare pragma autonomous_transaction; begin update toys set price = 99.00; commit; end; / select * from toys; commit; select * from toys;
以下是在LiveSQL中執行時的結果:
Oracle僅支援兩個隔離級別:Read Committed和Serializable。
閱讀已提交
這是Oracle資料庫的預設模式。使用read committed,您具有語句級一致性。這意味著每個DML命令(選擇,插入,更新或刪除)都可以在開始之前檢視儲存的所有資料。其他會話啟動後儲存的任何更改都將被隱藏。
它使用多版本併發控制(MVCC)來實現。更新或刪除行時,會將行的當前狀態儲存在undo中。因此,其他事務可以使用此撤消來檢視過去存在的資料。
序列化
將事務設定為可序列化時,資料庫就像您是資料庫的唯一使用者一樣。其他交易所做的更改對您隱藏。Serializable還會阻止您更改由此錯誤導致的其他事務修改的行: