SQL 事務簡介


  • 學習重點
  • 事務是需要在同一個處理單元中執行的一系列更新處理的集合。通過使用事務,可以對數據庫中的數據更新處理的提交和取消進行管理。
  • 事務處理的終止指令包括 COMMIT(提交處理)和 ROLLBACK(取消處理)兩種。
  • DBMS 的事務具有原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)四種特性。通常將這四種特性的首字母結合起來,統稱為 ACID 特性。

一、什么是事務

估計有些讀者對事務(transaction)這個詞並不熟悉,它通常被用於商務貿易或者經濟活動中,但是在 RDBMS 中,事務是對表中數據進行更新的單位。簡單來講,事務就是需要在同一個處理單元中執行的一系列更新處理的集合

KEYWORD

  • 事務

如前幾篇所述,對表進行更新需要使用 INSERTDELETE 或者 UPDATE 三種語句。但通常情況下,更新處理並不是執行一次就結束了,而是需要執行一系列連續的操作。這時,事務就能體現出它的價值了。

說到事務的例子,請大家思考一下下述情況。

現在,請大家把自己想象為管理 Product(商品)表的程序員或者軟件工程師。銷售部門的領導對你提出了如下要求。

“某某,經會議討論,我們決定把運動 T 恤的銷售單價下調 1000 日元,同時把 T 恤衫的銷售單價上浮 1000 日元,麻煩你去更新一下數據庫。”

由於大家已經學習了更新數據的方法 —— 只需要使用 UPDATE 進行更新就可以了,所以肯定會直接回答“知道了,請您放心吧”。

此時的事務由如下兩條更新處理所組成。

  • 更新商品信息的事務

    ① 將運動T恤的銷售單價降低 1000 日元

    UPDATE Product
    SET sale_price = sale_price - 1000
    WHERE product_name = '運動T恤';
    

    ② 將T恤衫的銷售單價上浮 1000 日元

    UPDATE Product
    SET sale_price = sale_price + 1000
    WHERE product_name = 'T恤衫';
    

上述 ① 和 ② 的操作一定要作為同一個處理單元執行。如果只執行了 ① 的操作而忘記了執行 ② 的操作,或者反過來只執行了 ② 的操作而忘記了執行 ① 的操作,一定會受到領導的嚴厲批評。遇到這種需要在同一個處理單元中執行一系列更新操作的情況,一定要使用事務來進行處理。

法則 7

事務是需要在同一個處理單元中執行的一系列更新處理的集合。

一個事務中包含多少個更新處理或者包含哪些處理,在 DBMS 中並沒有固定的標准,而是根據用戶的要求決定的(例如,運動 T 恤和 T 恤衫的銷售單價需要同時更新這樣的要求,DBMS 是無法了解的)。

二、創建事務

如果想在 DBMS 中創建事務,可以按照如下語法結構編寫 SQL 語句。

語法 6 事務的語法

事務開始語句;

      DML語句①;
      DML語句②;
      DML語句③;
         .
         .
         .
事務結束語句(COMMIT或者ROLLBACK);

使用事務開始語句和事務結束語句,將一系列 DML 語句(INSERT/UPDATE/DELETE 語句)括起來,就實現了一個事務處理。

這時需要特別注意的是事務的開始語句 [1]。實際上,在標准 SQL 中並沒有定義事務的開始語句,而是由各個 DBMS 自己來定義的。比較有代表性的語法如下所示。

  • SQL Server、PostgreSQL

    BEGIN TRANSACTION

  • MySQL

    START TRANSACTION

  • Oracle、DB2

KEYWORD

  • BEGIN TRANSACTION

  • START TRANSACTION

例如使用之前的那兩個 UPDATE(① 和 ②)創建出的事務如代碼清單 21 所示。

代碼清單 21 更新商品信息的事務

SQL Server PostgreSQL

BEGIN TRANSACTION;

    -- 將運動T恤的銷售單價降低1000日元
    UPDATE Product
       SET sale_price = sale_price - 1000
     WHERE product_name = '運動T恤';

    -- 將T恤衫的銷售單價上浮1000日元
    UPDATE Product
       SET sale_price = sale_price + 1000
     WHERE product_name = 'T恤衫';

COMMIT;

MySQL

START TRANSACTION;

    -- 將運動T恤的銷售單價降低1000日元
    UPDATE Product
       SET sale_price = sale_price - 1000
     WHERE product_name = '運動T恤';

    -- 將T恤衫的銷售單價上浮1000日元
    UPDATE Product
       SET sale_price = sale_price + 1000
     WHERE product_name = 'T恤衫';

COMMIT;

Oracle DB2

-- 將運動T恤的銷售單價降低1000日元
UPDATE Product
   SET sale_price = sale_price - 1000
 WHERE product_name = '運動T恤';

-- 將T恤衫的銷售單價上浮1000日元
UPDATE Product
   SET sale_price = sale_price + 1000
 WHERE product_name = 'T恤衫';

COMMIT;

如上所示,各個 DBMS 事務的開始語句都不盡相同,其中 Oracle 和 DB2 並沒有定義特定的開始語句。可能大家覺得這樣的設計很巧妙,其實是因為標准 SQL 中規定了一種悄悄開始事務處理 [2] 的方法。因此,即使是經驗豐富的工程師也經常會忽略事務處理開始的時間點。大家可以試着通過詢問“是否知道某個 DBMS 中事務是什么時候開始的”,來測試學校或者公司前輩的數據庫知識。

反之,事務的結束需要用戶明確地給出指示。結束事務的指令有如下兩種。

  • COMMIT——提交處理

    COMMIT 是提交事務包含的全部更新處理的結束指令(圖 3),相當於文件處理中的覆蓋保存。一旦提交,就無法恢復到事務開始前的狀態了。因此,在提交之前一定要確認是否真的需要進行這些更新。

    KEYWORD

    • COMMIT

    • 提交

    COMMIT 的流程 = 直線進行

    圖 3 COMMIT 的流程 = 直線進行

    萬一由於誤操作提交了包含錯誤更新的事務,就只能回到重新建表、重新插入數據這樣繁瑣的老路上了。由於可能會造成數據無法恢復的后果,請大家一定要注意(特別是在執行 DELETE 語句的 COMMIT 時尤其要小心)。

    法則 8

    雖然我們可以不清楚事務開始的時間點,但是在事務結束時一定要仔細進行確認。

  • ROLLBACK——取消處理

    ROLLBACK 是取消事務包含的全部更新處理的結束指令(圖 4),相當於文件處理中的放棄保存。一旦回滾,數據庫就會恢復到事務開始之前的狀態(代碼清單 22)。通常回滾並不會像提交那樣造成大規模的數據損失。

    KEYWORD

    • ROLLBACK

    • 回滾

    ROLLBACK 的流程 = 掉頭回到起點

    圖 4 ROLLBACK 的流程 = 掉頭回到起點

    代碼清單 22 事務回滾的例子

    SQL Server PostgreSQL

    BEGIN TRANSACTION; ------------------- ①
    
        -- 將運動T恤的銷售單價降低1000日元
        UPDATE Product
        SET sale_price = sale_price - 1000
        WHERE product_name = '運動T恤';
    
        -- 將T恤衫的銷售單價上浮1000日元
        UPDATE Product
        SET sale_price = sale_price + 1000
        WHERE product_name = 'T恤衫';
    
    ROLLBACK;
    

    特定的 SQL

    至此,我們已經知道各個 DBMS 中關於事務的語法不盡相同。代碼清單 22 中的語句在 MySQL 中執行時需要將 ① 語句改寫為“START TRANSACTION”,而在 Oracle 和 DB2 中執行時則無需 ① 語句(請將其刪除),具體請參考 創建事務

    上述事務處理執行之后,表中的數據不會發生任何改變。這是因為執行最后一行的 ROLLBACK 之后,所有的處理都被取消了。因此,回滾執行起來就無需像提交時那樣小心翼翼了(即使是想要提交的情況,也只需要重新執行事務處理就可以了)。

專欄

事務處理何時開始

之前我們說過,事務並沒有標准的開始指令存在,而是根據 DBMS 的不同而不同。

實際上,幾乎所有的數據庫產品的事務都無需開始指令。這是因為大部分情況下,事務在數據庫連接建立時就已經悄悄開始了,並不需要用戶再明確發出開始指令。例如,使用 Oracle 時,數據庫連接建立之后,第一條 SQL 語句執行的同時,事務就已經悄悄開始了。

像這樣不使用指令而悄悄開始事務的情況下,應該如何區分各個事務呢?通常會有如下兩種情況。

A: 每條 SQL 語句就是一個事務(自動提交模式

B: 直到用戶執行 COMMIT 或者 ROLLBACK 為止算作一個事務

KEYWORD

  • 自動提交模式

通常的 DBMS 都可以選擇其中任意一種模式。默認使用自動提交模式的 DBMS 有 SQL Server、PostgreSQL 和 MySQL 等 [3] DML 語句如下所示,每一條語句都括在事務的開始語句和結束語句之中。

BEGIN TRANSACTION;
   -- 將運動T恤的銷售單價降低1000日元
   UPDATE Product
      SET sale_price = sale_price - 1000
    WHERE product_name = '運動T恤';
COMMIT;

BEGIN TRANSACTION;
   -- 將T恤衫的銷售單價上浮1000日元
   UPDATE Product
      SET sale_price = sale_price + 1000
    WHERE product_name = 'T恤衫';
COMMIT;

在默認使用 B 模式的 Oracle 中,事務都是直到用戶自己執行提交或者回滾指令才會結束。

自動提交的情況需要特別注意的是 DELETE 語句。如果不是自動提交,即使使用 DELETE 語句刪除了數據表,也可以通過 ROLLBACK 命令取消該事務的處理,恢復表中的數據。但這僅限於明示開始事務,或者關閉自動提交的情況。如果不小心在自動提交模式下執行了 DELETE 操作,即使再回滾也無濟於事了。這是一個很嚴重的問題,初學者難免會碰到這樣的麻煩。一旦誤刪了數據,如果無法重新插入,是不是想哭的心都有了?所以一定要特別小心。

三、ACID 特性

DBMS 的事務都遵循四種特性,將這四種特性的首字母結合起來統稱為 ACID 特性。這是所有 DBMS 都必須遵守的規則。

KEYWORD

  • ACID 特性
  • 原子性(Atomicity)

    KEYWORD

    • 原子性(Atomicity)

    原子性是指在事務結束時,其中所包含的更新處理要么全部執行,要么完全不執行,也就是要么占有一切要么一無所有。例如,在之前的例子中,在事務結束時,絕對不可能出現運動 T 恤的價格下降了,而 T 恤衫的價格卻沒有上漲的情況。該事務的結束狀態,要么是兩者都執行了(COMMIT),要么是兩者都未執行(ROLLBACK)。

    從事務中途停止的角度去考慮,就能比較容易理解原子性的重要性了。由於用戶在一個事務中定義了兩條 UPDATE 語句,DBMS 肯定不會只執行其中一條,否則就會對業務處理造成影響。

  • 一致性(Consistency)

    一致性指的是事務中包含的處理要滿足數據庫提前設置的約束,如主鍵約束或者 NOT NULL 約束等。例如,設置了 NOT NULL 約束的列是不能更新為 NULL 的,試圖插入違反主鍵約束的記錄就會出錯,無法執行。對事務來說,這些不合法的 SQL 會被回滾。也就是說,這些 SQL 處理會被取消,不會執行。

    一致性也稱為完整性(圖 5)。

    KEYWORD

    • 一致性(Consistency)

    • 完整性

    保持完整性的流程

    圖 5 保持完整性的流程

  • 隔離性(Isolation)

    隔離性指的是保證不同事務之間互不干擾的特性。該特性保證了事務之間不會互相嵌套。此外,在某個事務中進行的更改,在該事務結束之前,對其他事務而言是不可見的。因此,即使某個事務向表中添加了記錄,在沒有提交之前,其他事務也是看不到新添加的記錄的。

    KEYWORD

    • 隔離性(Isolation)
  • 持久性(Durability)

    持久性也可以稱為耐久性,指的是在事務(不論是提交還是回滾)結束后,DBMS 能夠保證該時間點的數據狀態會被保存的特性。即使由於系統故障導致數據丟失,數據庫也一定能通過某種手段進行恢復。

    如果不能保證持久性,即使是正常提交結束的事務,一旦發生了系統故障,也會導致數據丟失,一切都需要從頭再來。

    保證持久性的方法根據實現的不同而不同,其中最常見的就是將事務的執行記錄保存到硬盤等存儲介質中(該執行記錄稱為日志)。當發生故障時,可以通過日志恢復到故障發生前的狀態。

    KEYWORD

    • 持久性(Durability)

    • 日志

請參閱

(完)


  1. 與之相對,事務結束語句只有 COMMITROLLBACK 兩種,在所有的 RDBMS 中都是通用的。 ↩︎

  2. 《標准 SQL 手冊修訂第 4 版》中的記述:希望大家注意事務默認開始的時間點。沒有“BEGIN TRANSACTION”這樣明確的開始標志。 ↩︎

  3. 例如,PostgreSQL 的用戶手冊中有如下記述:“PostgreSQL 中所有的 SQL 指令語句都在事務內執行。即使不執行 BEGIN,這些命令語句也會在執行時悄悄被括在 BEGINCOMMIT(如果成功的話)之間。”(《PostgreSQL 9.5.2 文檔》“3-4 節事務”) ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM