本章介紹什么是事務(wù)處理以及如何利用 COMMIT 和 ROLLBACK 語句來管理事務(wù)處理
20.1 事務(wù)處理
事務(wù)處理可以用來維護(hù)數(shù)據(jù)庫的完整性猜敢,它保證成批的 SQL 操作要么完全執(zhí)行,要么完全不執(zhí)行
正如第 12 章所述枫攀,關(guān)系數(shù)據(jù)庫設(shè)計(jì)把數(shù)據(jù)存儲(chǔ)在多個(gè)表中凯旭,使數(shù)據(jù)更容易操縱惫霸、維護(hù)和重用封恰。不用深究如何以及為什么進(jìn)行關(guān)系數(shù)據(jù)庫設(shè)計(jì),在某種程度上說越庇,設(shè)計(jì)良好的數(shù)據(jù)庫模式都是關(guān)聯(lián)的罩锐。
前面章中使用的 Orders 表就是一個(gè)很好的例子。
訂單存儲(chǔ)在 Orders 和 OrderItems 兩個(gè)表中:Orders 存儲(chǔ)實(shí)際的訂單悦荒,而 OrderItems 存儲(chǔ)訂購的各項(xiàng)物品唯欣。這兩個(gè)表使用主鍵互相關(guān)聯(lián)。這兩個(gè)表又與包含客戶和產(chǎn)品信息的其他表相關(guān)聯(lián)搬味。
給系統(tǒng)添加訂單的過程如下:
1.檢查數(shù)據(jù)庫中是否存在相應(yīng)的客戶境氢,如果不存在蟀拷,添加他/她
2.檢索客戶的 ID
3.添加一行到 Orders 表,把它與客戶 ID 關(guān)聯(lián)
4.檢索 Orders 表中賦予的新訂單 ID
5.對(duì)于訂購的每個(gè)物品在 OrderItems 表中添加一行萍聊,通過檢索出來的 ID 把它與 Orders 表關(guān)聯(lián)(以及通過產(chǎn)品 ID 與 Products 表關(guān)聯(lián))
假如由于某種數(shù)據(jù)庫故障(如超出磁盤空間问芬、安全限制、表鎖等)阻止了這個(gè)過程的完成寿桨。那么數(shù)據(jù)庫中的數(shù)據(jù)會(huì)出現(xiàn)什么情況此衅?
- 如果故障發(fā)生在添加了客戶之后,Orders 表添加之前亭螟,那么不會(huì)有什么問題
- 因?yàn)槟承┛蛻魶]有訂單是完全合法的
- 如果故障發(fā)生在 Orders 行插入之后挡鞍,OrderItems 添加之前,數(shù)據(jù)庫中則會(huì)有一個(gè)空訂單
- 如果系統(tǒng)在添加 OrderItems 行之中出現(xiàn)故障预烙,數(shù)據(jù)庫中存在不完整的訂單墨微,而且還不知道
這就需要使用事務(wù)處理:事務(wù)處理是一種機(jī)制,用來管理必須成批執(zhí)行的 SQL 操作扁掸,以保證數(shù)據(jù)庫不包含不完整的操作結(jié)果
利用事務(wù)處理翘县,可以保證一組操作不會(huì)中途停止,它們或者作為整體執(zhí)行谴分,或者完全不執(zhí)行
如果沒有錯(cuò)誤發(fā)生锈麸,整組語句提交給(寫到)數(shù)據(jù)庫表;
如果發(fā)生錯(cuò)誤牺蹄,則進(jìn)行回退(撤銷)以恢復(fù)數(shù)據(jù)庫到某個(gè)已知且安全的狀態(tài)
因此忘伞,請(qǐng)看相同的例子,這次我們說明過程如何工作:
1.檢查數(shù)據(jù)庫中是否存在相應(yīng)的客戶钞馁,如果不存在虑省,添加他/她
2.提交客戶信息
3.檢索客戶的 ID
4.添加一行到 Orders 表
5.如果在添加行到 Orders 表時(shí)出現(xiàn)故障匿刮,則回退
6.檢索 Orders 表中賦予的新訂單 ID
7.對(duì)于訂購的每項(xiàng)物品僧凰,添加新行到 OrderItems 表
8.如果在添加新行到 OrderItems 時(shí)出現(xiàn)故障,回退所有添加的 OrderItems 行和 Orders 行
有關(guān)事務(wù)處理需要知道的幾個(gè)術(shù)語:
- 事務(wù)指一組 SQL 語句
- 回退指撤銷指定 SQL 語句的過程
- 提交指將未存儲(chǔ)的 SQL 語句結(jié)果寫入數(shù)據(jù)庫表
- 保留點(diǎn)指事務(wù)處理中設(shè)置的臨時(shí)占位符熟丸,你可以對(duì)它發(fā)布回退(與回退整個(gè)事務(wù)處理不同)
可以回退哪些語句训措?
事務(wù)處理用來管理 INSERT、UPDATE 和 DELETE 語句
不能回退 SELECT 語句光羞,也不能回退 CREATE 或 DROP 操作
20.2 控制事務(wù)處理
下面討論事務(wù)處理的管理中所涉及的問題
管理事務(wù)處理的關(guān)鍵在于將 SQL 語句組分解為邏輯塊绩鸣,并明確規(guī)定數(shù)據(jù)何時(shí)應(yīng)該回退,何時(shí)不應(yīng)該回退
有的 DBMS 要求明確標(biāo)識(shí)事務(wù)處理塊的開始和結(jié)束纱兑,如在 SQL Server 中呀闻,標(biāo)識(shí)如下:
BEGIN TRANSACTION
...
COMMIT TRANSACTION
MySQL 中等同的代碼為:
START TRANSATCION
...
在 Oracle 數(shù)據(jù)庫中,沒有提供開始事務(wù)處理語句潜慎,所有的事務(wù)都是隱式開始的捡多,也就是說在 Oracle 中蓖康,用戶不可以顯示使用命令來開始一個(gè)事務(wù)
Oracle 任務(wù)第一條修改數(shù)據(jù)庫的語句,或者一些要求事務(wù)處理的場(chǎng)合都是事務(wù)的隱式開始
20.2.1 使用 ROLLBACK
SQL 的 ROLLBACK 命令用來回退(撤銷)SQL 語句垒手,請(qǐng)看下面的語句:
DELETE FROM Orders;
ROLLBACK;
20.2.2 使用 COMMIT
一般的 SQL 語句都是直接針對(duì)數(shù)據(jù)庫表執(zhí)行和編寫的蒜焊,這就是所謂的隱含提交,也就是提交(寫或保存)操作都是自動(dòng)進(jìn)行的
但是科贬,在事務(wù)處理塊中泳梆,提交不會(huì)隱含地進(jìn)行,為進(jìn)行明確的提交榜掌,需要使用 COMMIT 語句优妙。
看一個(gè) SQL Server 的例子:
BEGIN TRANSACTION
DELETE OrderItems WHERE order_num = 12345
DELETE Orders WHERE order_num = 12345
COMMIT TRANSACTION
為在 Oracle 中完成相同的工作,可如下進(jìn)行:
DELETE OrderItems WHERE order_num = 12345;
DELETE Orders WHERE order_num = 12345;
COMMIT;
20.2.3 使用保留點(diǎn)
簡(jiǎn)單的 ROLLBACK 和 COMMIT 語句就可以寫入或撤銷整個(gè)事務(wù)處理憎账。
但是鳞溉,這只是針對(duì)簡(jiǎn)單的事務(wù)處理才能這樣做,更復(fù)雜的事務(wù)處理可能需要部分提交或回退
例如鼠哥,前面描述的添加訂單的過程為事務(wù)處理熟菲。如果發(fā)生錯(cuò)誤,只需要返回到添加 Orders 行之前即可朴恳。不需要回退到 Customers 表(如果存在的話)抄罕。
為了完成這樣的事情,必須在事務(wù)處理中合適的位置放置占位符于颖。這樣呆贿,如果需要回退,就可以回退到某個(gè)占位符森渐,
在 SQL 中做入,這些占位符稱為保留點(diǎn)
為了在 MySQL 和 Oracle 中創(chuàng)建占位符,可如下使用 SAVEPOINT 語句:
SAVEPOINT delete1;
每個(gè)保留點(diǎn)都取標(biāo)識(shí)它的唯一名字同衣,以便在回退時(shí)竟块,DBMS 知道要回退到何處。
為了回退到上面給出的保留點(diǎn)耐齐,在 MySQL 和 Oracle 中浪秘,可如下進(jìn)行:
ROLLBACK TO delete1;
保留點(diǎn)越多越好:保留點(diǎn)越多,就越能按自己的意愿靈活地進(jìn)行回退