定義
DBMS 提供了事務(wù)(Transactions)支持谣旁。事務(wù)是作為 DBMS 中的邏輯單元分組執(zhí)行的一系列數(shù)據(jù)庫(kù)操作蛮穿。與在DBMS之外執(zhí)行程序(例如祟绊,C程序)在許多方面都不同甚牲!
數(shù)據(jù)庫(kù)應(yīng)用程序通常通過事務(wù)而不是單個(gè)操作訪問數(shù)據(jù)庫(kù)镶苞。例如,大型數(shù)據(jù)庫(kù)和數(shù)百個(gè)并發(fā)用戶:銀行迂尝、超市收銀臺(tái)脱茉、機(jī)票預(yù)訂、在線購(gòu)買等垄开。
之所以使用事務(wù)是因?yàn)樗鼈兛梢栽谝韵虑闆r下實(shí)施數(shù)據(jù)完整性:多個(gè)用戶可以同時(shí)修改和共享數(shù)據(jù)琴许;事務(wù)、系統(tǒng)和媒體故障可能不時(shí)發(fā)生溉躲。
- 從高級(jí)語(yǔ)言的角度(如 SQL)
- 插入(INSERT)榜田、選擇(SELECT)、更新(UPDATE)锻梳、刪除(DELETE)
- 開始(BEGIN)箭券、提交(COMMIT)、中止(ABORT)/ 回滾(ROLLBACK)等;
BEGIN TRANSACTION
SELECT balance FROM Account WHERE name = `Steve';
UPDATE Account
SET balance = balance-500 WHERE name=`Steve';
SELECT balance FROM Account WHERE name = `Bob';
UPDATE Account
SET balance = balance+500 WHERE name = `Bob';
COMMIT
- 內(nèi)部進(jìn)程級(jí)別:操作對(duì)象為數(shù)據(jù)表唱蒸、行邦鲫、單元或者內(nèi)存頁(yè)。
- 讀(read)神汹、寫(write)
- 開始(begin)庆捺、提交(commit)
- 中止(abort):表示事務(wù)未成功結(jié)束,撤消事務(wù)的所有操作
步驟 | Transactions |
---|---|
1 | read(A) |
2 | write(A) (A := A - 500) |
3 | read(B) |
4 | write(B) (B:= B + 500) |
5 | commit |
其中屁魏,A 是 Steve 的賬戶余額滔以;B 是 Bob 的賬戶余額。
ACID 屬性
DBMS 確保了事務(wù)的以下屬性:
- 原子性(Atomicity)
- 每個(gè)事務(wù)的執(zhí)行都是原子性的氓拼,即要么所有的操作都完成了(ALL)你画,要么根本沒有完成(NONE)。
- 如果一個(gè)事務(wù)因?yàn)槟承┰蚨荒芡瓿商已敲?DBMS 必須消除部分事務(wù)的影響坏匪,以確保原子性。
- 一致性(Consistency)
- 數(shù)據(jù)庫(kù)的狀態(tài)在每個(gè)事務(wù)之前和之后是一致的撬统。
- 中間狀態(tài)可能是不一致的适滓。
- 隔離(Isolation)
- 每個(gè)事務(wù)的執(zhí)行結(jié)果應(yīng)該不受其他并發(fā)執(zhí)行事務(wù)的影響。
- 其他事務(wù)不會(huì)看到目前事務(wù)下所有對(duì)象的信息恋追,直至該事務(wù)完成凭迹。
- 耐用性(Dutability)
??????? - 一旦事務(wù)成功完成,它的效果應(yīng)該會(huì)保存在數(shù)據(jù)庫(kù)中苦囱。- 一旦提交嗅绸,事務(wù)就不能恢復(fù)為 abort,這種改變是持久的撕彤。
需要注意的是鱼鸠,這些屬性不是相互獨(dú)立的,但原子性是中心屬性。
一致性(Consistency)由應(yīng)用開發(fā)者實(shí)現(xiàn)蚀狰,因?yàn)檫@要求開發(fā)者理解應(yīng)用程序的數(shù)據(jù)模型漆弄,并且確保每個(gè)事務(wù)都以一種與現(xiàn)實(shí)世界中的合法更改相一致的方式更改數(shù)據(jù)。
而其他三種屬性則由事務(wù)管理器實(shí)現(xiàn)造锅,最常用的技術(shù)有兩種:
- 鎖(Locking)—— 用于并發(fā)控制,如兩階段鎖(2PL:Two-phase Locking)
- 日志(Logging)—— 用于恢復(fù)廉邑,如預(yù)寫式日志(WAL:Write-Ahead Log)
鎖(Locking)
鎖是一種用于并發(fā)控制的技術(shù)哥蔚,可保證事務(wù)的隔離性。鎖在數(shù)據(jù)庫(kù)中一般作用在對(duì)象上蛛蒙,如文件糙箍、表、記錄牵祟、頁(yè)等深夯。
鎖的用法分成兩類:
- 共享鎖:多個(gè)事務(wù)可以同時(shí)獲取它。
- 互斥鎖:只有一個(gè)事務(wù)可以獲得它诺苹,導(dǎo)致其他試圖獲取它的事務(wù)等待咕晋。持有鎖的事務(wù)完成后,它釋放鎖收奔,允許一個(gè)等待的事務(wù)獲取鎖掌呜。
兩階段鎖(2PL:Two-phase Locking)
鎖的使用和移除分為兩個(gè)階段:
- 展開:獲取鎖,不釋放鎖坪哄。
- 收縮:釋放鎖质蕉,不獲取鎖。
2PL 基本協(xié)議使用兩種類型的鎖:
- 共享鎖(read-lock):在讀取對(duì)象之前通過事務(wù)與對(duì)象關(guān)聯(lián)翩肌。
- 互斥鎖(write-lock):在寫對(duì)象之前通過事務(wù)與對(duì)象關(guān)聯(lián)模暗。
當(dāng)讀寫鎖同時(shí)出現(xiàn)在一個(gè)對(duì)象身上的時(shí)候,鎖之間的兼容滿足以下關(guān)系:
鎖的類型 | 讀鎖(read-lock) | 寫鎖(write-lock) |
---|---|---|
讀鎖(read-lock) | 兼容 | 不兼容 |
寫鎖(write-lock) | 不兼容 | 不兼容 |
缺點(diǎn):在某些情況下念祭,2PL可以從根本上限制事務(wù)間的交叉
優(yōu)點(diǎn):2PL使交叉變得安全兑宇,比如保證事務(wù)的可串行性。
可串行化(Serializability)意味著產(chǎn)生的數(shù)據(jù)庫(kù)狀態(tài)等于以串行方式運(yùn)行事務(wù)的數(shù)據(jù)庫(kù)狀態(tài)棒卷。
可串行性是并發(fā)事務(wù)的主要正確性標(biāo)準(zhǔn)顾孽。
但是,2PL可能會(huì)出現(xiàn)死鎖比规,即若厚,兩個(gè)或多個(gè)事務(wù)的相互阻塞,比如一下的情況:
T1 | T2 | 解釋 |
---|---|---|
lock-r(A) | T1獲取了A的讀鎖 | |
read(A) | ||
lock-r(B) | T2獲取了B的讀鎖蜒什,與A的讀鎖相互不影響 | |
read(B) | ||
lock-w(B) | T1想獲取B的寫鎖测秸,但是需要等待T2釋放B的讀鎖才能獲取到 | |
write(B) | ||
lock-w(A) | ||
write(A) | T2想獲取A的寫鎖,但是需要等待T1釋放A的讀鎖才能獲取到 |
如何使用鎖定技術(shù)提高并發(fā)性?
- 細(xì)化鎖類型
- 區(qū)分讀鎖和寫鎖霎冯。
- 讀操作通常比寫操作更頻繁铃拇,而且讀同一個(gè)對(duì)象的多個(gè)事務(wù)不會(huì)相互干擾
- 鎖定粒度
- 數(shù)據(jù)庫(kù) > 表 > 記錄 > 頁(yè)面 > 數(shù)據(jù)庫(kù)表頁(yè)記錄
- Table-level locks > Record-level locks
- 放松隔離(Isolation)的概念
日志(Logging)
日志是一種用于恢復(fù)的技術(shù),可保證事務(wù)的原子性和持續(xù)性沈撞。日志是一個(gè)僅追加(append-only)的文件慷荔,它記錄對(duì)對(duì)象的建議更改。當(dāng)多個(gè)事務(wù)并發(fā)運(yùn)行時(shí)缠俺,日志記錄是交錯(cuò)的显晶。
恢復(fù)相當(dāng)于撤銷或重做日志中的更改:
- 撤銷(Undo)尚未提交的操作。
- 重新執(zhí)行(Redo)已提交但尚未寫入磁盤的操作壹士。
原子性(Atomicity)是通過定義當(dāng)且僅當(dāng)日志中記錄了更改時(shí)才提交事務(wù)來實(shí)現(xiàn)的磷雇。
持久性(Durability)是通過在系統(tǒng)啟動(dòng)時(shí)讀取日志并確保每個(gè)提交的事務(wù)都在數(shù)據(jù)庫(kù)中應(yīng)用了其更改來實(shí)現(xiàn)的。
預(yù)寫式日志(WAL:Write-Ahead Log)
預(yù)寫式日志(WAL)是最基本的規(guī)則躏救,它確保在嘗試從崩潰中恢復(fù)時(shí)唯笙,數(shù)據(jù)庫(kù)的每個(gè)更改記錄都是可用的。
主要思想:
- 對(duì)對(duì)象的任何更改都首先記錄在日志中盒使,即崩掘,包含該對(duì)象的舊值和新值的記錄。
- 在提交事務(wù)之前少办,必須將日志中的記錄寫入持久存儲(chǔ)呢堰。
因此,提交事務(wù)的定義為:“日志記錄(包括提交記錄)已寫入持久存儲(chǔ)的事務(wù)”凡泣。
對(duì)于一個(gè)日志記錄來說枉疼,其典型的字段為:
- LSN:每一個(gè)日志記錄都有一個(gè)獨(dú)一無二的日志序列碼(Log Sequence Number)
- prevLSN:同一個(gè)事物中上一個(gè)日志記錄的序列碼
- transID
- type:日志內(nèi)容的類型,包括 update鞋拟,commit骂维,abort,end 等等
- 對(duì)于更新的日志記錄贺纲,可能還會(huì)有 pageID航闺,length,offset猴誊,before-image潦刃,after-image
WAL 對(duì)性能的提升體現(xiàn)在:
- 通常會(huì)顯著減少磁盤寫的數(shù)量
- 支持對(duì)日志文件進(jìn)行一次同步,而不是對(duì)數(shù)據(jù)文件進(jìn)行多次同步
- 支持在線備份和時(shí)間點(diǎn)恢復(fù)
并發(fā)事務(wù)(Concurrent Transactions)
交錯(cuò)處理:事務(wù)交錯(cuò)在單個(gè)CPU中懈叹。
并行處理:事務(wù)在多個(gè)cpu中并行執(zhí)行乖杠。
使用并發(fā)同時(shí)執(zhí)行事務(wù)將提高數(shù)據(jù)庫(kù)性能,具體包括:
- 增加吞吐量(已完成事務(wù)的平均數(shù)量)
- 例如澄成,當(dāng)一個(gè)事務(wù)正在等待從磁盤讀取一個(gè)對(duì)象時(shí)胧洒,CPU可以處理另一個(gè)事務(wù)
- (因?yàn)?I/O 活動(dòng)可以與 CPU 活動(dòng)并行執(zhí)行)
- 減少延遲(完成事務(wù)的平均時(shí)間)
- 例如畏吓,短事務(wù)與長(zhǎng)事務(wù)的交錯(cuò)執(zhí)行通常允許短事務(wù)更快地完成。
但是 DBMS 必須保證事務(wù)的交錯(cuò)不會(huì)導(dǎo)致數(shù)據(jù)庫(kù)的不一致卫漫,也就是說要實(shí)現(xiàn)并發(fā)控制菲饼。
并發(fā)控制的實(shí)現(xiàn)主要是為了要防止以下的問題:
- 丟失更新問題(The lost update problem)
- 寫入沖突(write-write conflicts)
- 當(dāng)兩個(gè)事務(wù)更新同一對(duì)象時(shí)發(fā)生,且一個(gè)事務(wù)可能會(huì)覆蓋已由另一個(gè)事務(wù)更新的對(duì)象的值
- 骯臟讀取問題(The dirty read problem)
- 寫讀沖突(write-read conflicts)
- 當(dāng)一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)更新但尚未提交的對(duì)象的值時(shí)發(fā)生
- 不可重復(fù)讀取問題(The unrepeated read problem)
- 讀寫沖突(read-write conflicts)
- 一個(gè)事務(wù)可以更改一個(gè)對(duì)象的值列赎,該對(duì)象已被另一個(gè)事務(wù)讀取宏悦,但仍在進(jìn)行中(可以為該對(duì)象發(fā)出兩個(gè)read,或在讀取該對(duì)象后發(fā)出一個(gè)write)
- 幽靈讀取問題(The phantom read problem)
- 當(dāng)一個(gè)事務(wù) T1 更新的元組滿足另一個(gè)事務(wù)的搜索條件時(shí)發(fā)生包吝,因此通過相同的搜索條件肛根,事務(wù)在不同的時(shí)間獲得不同的結(jié)果。
如果使用串行執(zhí)行事務(wù)的話漏策,就不會(huì)出現(xiàn) 骯臟讀取、不可重復(fù)讀取問題 和 幽靈讀取問題 這幾種情況了臼氨。
未重復(fù)讀取與幽靈讀取的差別
不可重復(fù)讀取 | 幽靈讀取 |
---|---|
執(zhí)行相同的選擇(SELECT)兩次會(huì)產(chǎn)生相同的元組集合掺喻,但是屬性值可能不同 | 執(zhí)行相同的選擇(SELECT)兩次會(huì)產(chǎn)生兩組不同的元組 |
讀取受另一個(gè)事務(wù)更新(UPDATE)影響的對(duì)象時(shí)可能發(fā)生 | 當(dāng)查詢一組從另一個(gè)事務(wù)中插入(INSERT)、刪除(DELETE)储矩、更新(UPDATE)中受影響的元組時(shí)可能發(fā)生 |
可以使用記錄級(jí)鎖定(record-level lock)來防止 | 可以使用表格級(jí)鎖定(table-level lock)來防止 |
也就是說感耙,對(duì)于由更新(UPDATE)造成的讀取不一致的情況,可以分別通過記錄級(jí)鎖定(record-level lock)和表格級(jí)鎖定(table-level lock)兩種類型的鎖來防止相應(yīng)的問題持隧。
SQL 對(duì)事務(wù)的支持
- SQL標(biāo)準(zhǔn)沒有強(qiáng)制實(shí)施特定的鎖定方案或強(qiáng)制執(zhí)行特定的行為
- 顯式事務(wù)可能沒有 BEGIN TRANSACTION 語(yǔ)句即硼,但必須以 COMMIT 或 ABORT (ROLLBACK) 語(yǔ)句結(jié)束。
- 當(dāng)沒有給出顯式的事務(wù)語(yǔ)句時(shí)屡拨,每個(gè)SQL語(yǔ)句都被認(rèn)為是一個(gè)事務(wù)只酥。
- 為了讓程序員對(duì)事務(wù)開銷有更多的控制,SQL允許他們指定隔離級(jí)別呀狼,即裂允。事務(wù)對(duì)并發(fā)事務(wù)準(zhǔn)備容忍的干擾程度。
核心思想就是哥艇,權(quán)衡性能(更好的并發(fā)訪問)與一致性(數(shù)據(jù)庫(kù)的完整性)
SQL-92 定義了事務(wù)隔離的4個(gè)級(jí)別:
- 未提交讀(Read Uncommitted)
- 已提交讀(Read Committed)
- 可重復(fù)讀(Repeatable Read)
- 串行(Serializable)
通過以下命令可以指定事務(wù)隔離的級(jí)別:
SET TRANSACTION ISOLATION LEVEL serializable;
不同的隔離級(jí)別排除了不同的問題:(限制由弱到強(qiáng))
隔離級(jí)別 | 含義 | 骯臟讀取 | 不可重復(fù)讀取 | 幽靈讀取 |
---|---|---|---|---|
未提交讀(Read Uncommitted) | 一個(gè)事務(wù)可以看到尚未提交的其他事務(wù)所做的更改绝编。這可能相當(dāng)危險(xiǎn)。在對(duì)只讀數(shù)據(jù)執(zhí)行查詢時(shí)使用它貌踏,或者在查詢是否返回未提交數(shù)據(jù)無關(guān)緊要的情況下使用它十饥。 | 出現(xiàn) | 出現(xiàn) | 出現(xiàn) |
已提交讀(Read Committed) | 一個(gè)事務(wù)只看到其他事務(wù)提交的更改。它是數(shù)據(jù)庫(kù)應(yīng)用程序中最常用的隔離級(jí)別祖乳。當(dāng)希望最大化應(yīng)用程序之間的并發(fā)性逗堵,但不希望查詢看到未提交的數(shù)據(jù)時(shí),可以使用它眷昆。 | 不出現(xiàn) | 出現(xiàn) | 出現(xiàn) |
可重復(fù)讀(Repeatable Read) | 事務(wù)所觸及的對(duì)象被鎖定砸捏,并且不能被并發(fā)事務(wù)更新或刪除谬运。當(dāng)希望應(yīng)用程序之間具有某種程度的并發(fā)性,但不希望在事務(wù)期間更改單個(gè)對(duì)象時(shí)垦藏,可以使用它 | 不出現(xiàn) | 不出現(xiàn) | 出現(xiàn) |
串行(Serializable) | 所有事務(wù)都與其他事務(wù)完全隔離梆暖。它是安全的,但可能會(huì)導(dǎo)致顯著的性能下降掂骏。當(dāng)希望應(yīng)用程序之間具有某種程度的并發(fā)性轰驳,但不希望在不同的時(shí)間運(yùn)行查詢時(shí)返回不同的結(jié)果集時(shí),可以使用它弟灼。 | 不出現(xiàn) | 不出現(xiàn) | 不出現(xiàn) |
更高的隔離級(jí)別減少了用戶可能遇到的并發(fā)問題的類型级解,但是需要更多的系統(tǒng)資源,并且增加了一個(gè)事務(wù)阻塞其他事務(wù)的機(jī)會(huì)田绑。
不同的 DBMS 實(shí)現(xiàn)隔離級(jí)別的方式非常不同勤哗。丟失更新所需的隔離級(jí)別取決于數(shù)據(jù)庫(kù)管理系統(tǒng)的實(shí)現(xiàn)。但一般來說掩驱,它可能需要最高的水平序列化來防止它芒划。
較低的隔離級(jí)別增加了許多用戶同時(shí)訪問數(shù)據(jù)的能力,但也增加了用戶可能會(huì)遇到并發(fā)性影響的數(shù)量
相反欧穴,更高的隔離級(jí)別減少了用戶可能遇到的并發(fā)影響的類型民逼,但是需要更多的系統(tǒng)資源,并增加了一個(gè)事務(wù)阻塞另一個(gè)事務(wù)的機(jī)會(huì)涮帘。
因此拼苍,選擇適當(dāng)?shù)母綦x級(jí)別取決于平衡應(yīng)用程序的數(shù)據(jù)完整性需求和每個(gè)隔離級(jí)別的開銷。