跳轉至內容

結構化查詢語言/事務

來自 Wikibooks,開放世界中的開放書籍

一個事務是一組一個或多個SQL語句 - 包含寫入資料庫的語句,例如INSERT、UPDATE或DELETE,SELECT命令也可以是事務的一部分。所有寫入語句必須是事務的一部分。事務的目的是保證資料庫的變化只從一個一致的狀態到另一個一致的狀態。它將所有中間狀態組合成一個更改事件。這在並行處理、磁碟崩潰、電源故障等關鍵情況下也適用。事務確保資料庫完整性

為此,它們支援四個基本屬性,這些屬性統稱為ACID 正規化

Atomic(原子性) 事務中的所有SQL語句要麼全部執行,要麼都不執行。
Consistent(一致性) 事務所有資料更改的總和將資料庫從一個一致狀態轉換為另一個一致狀態。
Isolated(隔離性) 隔離級別定義了未提交事務的哪些部分對其他會話可見。
Durable(永續性) 即使系統隨後崩潰,資料庫也會保留已提交的更改。

事務邊界

[編輯 | 編輯原始碼]

由於每個寫入資料庫的SQL語句都是事務的一部分,因此如果之前沒有語句啟動未完成的事務,DBMS會為每個語句隱式地啟動一個事務。或者,應用程式/會話可以透過命令START TRANSACTION顯式地啟動事務。

所有後續的SQL命令都是此事務的一部分。事務保持到確認或拒絕為止。確認透過命令COMMIT進行,拒絕透過命令ROLLBACK進行。在提交COMMIT或ROLLBACK命令之前,DBMS將每個寫入語句的結果儲存到一箇中間區域,該區域對其他會話不可見(參見:隔離級別)。同時使用COMMIT命令,此事務的所有更改最終進入公共資料庫,對每個其他會話可見,並且事務終止。如果COMMIT由於任何原因失敗,則與會話提交ROLLBACK命令時相同:此事務的所有更改都被丟棄,並且事務終止。可選地,會話可以透過提交單個命令ROLLBACK來撤消其屬於活動事務的所有寫入操作。

一個示例

-- Begin the transaction with an explicit command (In general not necessary. Not supported by Oracle.)
START TRANSACTION;
-- Insert some rows
INSERT ... ;
-- Modify those rows or some other rows
UPDATE ... ;
-- Delete some rows
DELETE ... ;
-- If the COMMIT succeeds, the results of the above 3 commands have been transferred to the 'common' 
-- database and thus 'published' to all other sessions.
COMMIT;
--
-- 
START TRANSACTION;
INSERT ... ;
UPDATE ... ;
DELETE ... ;
-- Discard INSERT, UPDATE and DELETE
ROLLBACK;

儲存點

[編輯 | 編輯原始碼]

由於事務可以包含許多語句,因此很可能出現執行時錯誤或邏輯錯誤。在某些此類情況下,應用程式希望僅回滾實際事務的一部分並提交其餘部分,或第二次恢復處理。為此,可以定義內部事務邊界,它反映了從事務開始到此時的所有處理。這些中間邊界稱為儲存點。COMMIT和ROLLBACK語句終止完整的事務,包括其儲存點。

-- Begin the transaction with an explicit command
START TRANSACTION;
--
INSERT ... ;
-- Define a savepoint
SAVEPOINT step_1;
--
UPDATE ... ;
-- Discard only the UPDATE. The INSERT remains.
ROLLBACK TO SAVEPOINT step_1;
-- try again (or do any other action)
UPDATE ... ;
-- confirm INSERT and the second UPDATE
COMMIT;

在事務的生命週期內,如果儲存點不再需要,則可以釋放它。(它在事務結束時會被隱式釋放。)

-- ...
-- ...
RELEASE SAVEPOINT <savepoint_name>;
-- This has no effect on the results of the previous INSERT, UPDATE or DELETE commands. It only eliminates the
-- possibility to ROLLBACK TO SAVEPOINT <savepoint_name>.

原子性

[編輯 | 編輯原始碼]

事務保證其所有語句的結果在邏輯級別上被視為單個操作。所有寫入語句都具有臨時性質,直到COMMIT命令成功終止。

此行為有助於確保業務邏輯的邏輯完整性。例如:如果要將一定數量的錢從一個賬戶轉到另一個賬戶,則必須修改資料庫中的至少兩行。第一個修改減少一行中的金額,第二個修改在另一行中增加金額。如果在這兩個寫操作之間發生磁碟崩潰或電源故障,則應用程式會出現問題。但是,事務的原子性屬性保證寫入操作都不會到達資料庫(在任何故障或ROLLBACK的情況下)或所有操作都到達資料庫(在成功COMMIT的情況下)。

在維基百科上可以找到有關原子性屬性的更多詳細資訊。

一致性

[編輯 | 編輯原始碼]

事務保證資料庫在終止後處於一致狀態。這種一致性發生在不同的級別

  • 資料和所有派生的索引條目同步。在大多數情況下,資料和索引條目儲存在資料庫內的不同區域。但是,在事務結束之後,這兩個區域都會更新(或都不更新)。
  • 表約束列約束可能會在事務期間(透過使用DEFERRABLE關鍵字)被違反,但在其終止後不會被違反。
  • 可能存在主鍵和外部索引鍵。在事務期間,外部索引鍵規則可能會被違反(透過使用DEFERRABLE關鍵字),但在其終止後不會被違反。
  • 資料庫的邏輯完整性不受保證!如果在上例的銀行賬戶中,應用程式忘記更新第二行,則會出現問題。

隔離性

[編輯 | 編輯原始碼]

在大多數情況下,許多會話同時在DBMS上工作。它們競爭資源,尤其是資料。只要資料沒有被修改,這不成問題。DBMS可以將資料傳遞給所有會話。

但是,如果多個會話嘗試在同一時間修改資料,則衝突是不可避免的。這是一個在航班預訂系統上工作的兩個會話的示例時間線。會話S1讀取航班的空餘座位數:1個空餘座位。S2讀取同一航班的空餘座位數:1個空餘座位。S1預訂最後一個座位。S2預訂最後一個座位。

對這類衝突進行分析的核心結果是,如果所有事務(涉及相同資料的事務)按順序執行:一個接一個,那麼所有衝突都是可以避免的。但很明顯,這種行為效率較低。如果DBMS儘可能多地並行工作,則整體效能會提高。SQL標準提供了對這類衝突的系統分類,並提供了SET TRANSACTION ...命令來解決這些衝突,目的是儘可能地允許並行操作。

隔離問題分類

[編輯 | 編輯原始碼]

標準確定了三種問題情景

  • P1(**髒讀**):"SQL事務T1修改一行。然後SQL事務T2在T1執行COMMIT之前讀取該行。如果T1隨後執行ROLLBACK,則T2將讀取一行從未提交過的資料,因此可以認為該行從未存在過。" [1]
  • P2(**不可重複讀**):"SQL事務T1讀取一行。然後SQL事務T2修改或刪除該行並執行COMMIT。如果T1隨後嘗試重新讀取該行,則它可能會收到修改後的值或發現該行已被刪除。" [1]不可重複讀涉及單個行。
  • P3(**幻讀**):"SQL事務T1讀取滿足某個搜尋條件的行集N。然後SQL事務T2執行生成一個或多個滿足SQL事務T1使用的搜尋條件的行SQL語句。如果SQL事務T1隨後使用相同的搜尋條件重複初始讀取,則它將獲得不同的行集合。" [1]幻讀涉及結果集。

避免隔離問題

[編輯 | 編輯原始碼]

根據應用程式的要求和訪問策略,上述某些問題可能是可以容忍的,而另一些則不可容忍。標準提供了SET TRANSACTION ...命令來定義在事務內允許發生哪些問題,以及不允許發生哪些問題。SET TRANSACTION ...命令必須是事務中的第一個語句。

-- define (un)tolerable conflict situations (Oracle does not support all of them)
SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED |
                                 READ COMMITTED   |
                                 REPEATABLE READ  |
                                 SERIALIZABLE];

下表顯示了每個級別可能發生哪些問題。

隔離級別 髒讀 不可重複讀 幻讀
讀取未提交 可能發生 可能發生 可能發生
讀取提交 - 可能發生 可能發生
可重複讀 - - 可能發生
序列化 - - -

在維基百科上,有更多關於隔離級別併發控制的詳細資訊和示例。

永續性

[編輯 | 編輯原始碼]

事務保證每個確認的寫操作都將(幾乎)在所有後續災難中倖存下來。為此,在大多數情況下,DBMS 不僅將更改寫入資料庫,還額外寫入日誌檔案,這些日誌檔案應位於不同的裝置上。因此,在磁碟崩潰後,可以從資料庫備份和這些日誌檔案中恢復所有更改。

在維基百科上可以找到關於永續性屬性的更多詳細資訊。

自動提交

[編輯 | 編輯原始碼]

一些DBMS在標準之外提供了AUTOCOMMIT功能。如果啟用此功能,則該功能會在每個寫入語句後自動提交COMMIT命令,從而導致無法回滾由大量SQL語句組成的邏輯工作單元。此外,無法使用SAVEPOINT功能。

在許多情況下,此功能預設處於啟用狀態。

參考文獻

[編輯 | 編輯原始碼]
  1. a b c "ISO/IEC 9075-2:2011: 資訊科技 -- 資料庫語言 -- SQL -- 第2部分:基礎(SQL/Foundation)".


華夏公益教科書