目錄
- 一、什么是事務
- 二、創建事務
- 三、ACID 特性
- 請參閱
- 學習重點
- 事務是需要在同一個處理單元中執行的一系列更新處理的集合,通過使用事務,可以對資料庫中的資料更新處理的提交和取消進行管理,
- 事務處理的終止指令包括
COMMIT(提交處理)和ROLLBACK(取消處理)兩種, - DBMS 的事務具有原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)四種特性,通常將這四種特性的首字母結合起來,統稱為 ACID 特性,
一、什么是事務
估計有些讀者對事務(transaction)這個詞并不熟悉,它通常被用于商務貿易或者經濟活動中,但是在 RDBMS 中,事務是對表中資料進行更新的單位,簡單來講,事務就是需要在同一個處理單元中執行的一系列更新處理的集合,
KEYWORD
- 事務
如前幾篇所述,對表進行更新需要使用 INSERT、DELETE 或者 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 -
提交

圖 3 COMMIT 的流程 = 直線進行
萬一由于誤操作提交了包含錯誤更新的事務,就只能回到重新建表、重新插入資料這樣繁瑣的老路上了,由于可能會造成資料無法恢復的后果,請大家一定要注意(特別是在執行
DELETE陳述句的COMMIT時尤其要小心),法則 8
雖然我們可以不清楚事務開始的時間點,但是在事務結束時一定要仔細進行確認,
-
-
ROLLBACK——取消處理ROLLBACK是取消事務包含的全部更新處理的結束指令(圖 4),相當于檔案處理中的放棄保存,一旦回滾,資料庫就會恢復到事務開始之前的狀態(代碼清單 22),通常回滾并不會像提交那樣造成大規模的資料損失,KEYWORD
-
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)
-
日志
-
請參閱
- 資料的插入
- 資料的洗掉
- 資料的更新
- 事務
(完)
與之相對,事務結束陳述句只有
COMMIT和ROLLBACK兩種,在所有的 RDBMS 中都是通用的, ??《標準 SQL 手冊修訂第 4 版》中的記述:希望大家注意事務默認開始的時間點,沒有“
BEGIN TRANSACTION”這樣明確的開始標志, ??例如,PostgreSQL 的用戶手冊中有如下記述:“PostgreSQL 中所有的 SQL 指令陳述句都在事務內執行,即使不執行
BEGIN,這些命令陳述句也會在執行時悄悄被括在BEGIN和COMMIT(如果成功的話)之間,”(《PostgreSQL 9.5.2 檔案》“3-4 節事務”) ??
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/374436.html
標籤:SQL Server
上一篇:SQL 資料的更新(UPDATE 陳述句的使用方法)
下一篇:SQL 視圖簡介
