【數(shù)據(jù)庫(kù)】數(shù)據(jù)庫(kù)入門(十二): 數(shù)據(jù)庫(kù)事務(wù)(Database Transactions)

定義

DBMS 提供了事務(wù)(Transactions)支持谣旁。事務(wù)是作為 DBMS 中的邏輯單元分組執(zhí)行的一系列數(shù)據(jù)庫(kù)操作蛮穿。與在DBMS之外執(zhí)行程序(例如祟绊,C程序)在許多方面都不同甚牲!

image

數(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ù)有兩種:

  1. 鎖(Locking)—— 用于并發(fā)控制,如兩階段鎖(2PL:Two-phase Locking)
  2. 日志(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中懈叹。


image

并行處理:事務(wù)在多個(gè)cpu中并行執(zhí)行乖杠。


image

使用并發(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í)別的開銷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末调缨,一起剝皮案震驚了整個(gè)濱河市疮鲫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弦叶,老刑警劉巖棚点,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異湾蔓,居然都是意外死亡瘫析,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門默责,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贬循,“玉大人,你說我怎么就攤上這事桃序≌认海” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵媒熊,是天一觀的道長(zhǎng)奇适。 經(jīng)常有香客問我坟比,道長(zhǎng),這世上最難降的妖魔是什么嚷往? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任葛账,我火速辦了婚禮,結(jié)果婚禮上皮仁,老公的妹妹穿的比我還像新娘籍琳。我一直安慰自己,他們只是感情好贷祈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布趋急。 她就那樣靜靜地躺著,像睡著了一般势誊。 火紅的嫁衣襯著肌膚如雪呜达。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天粟耻,我揣著相機(jī)與錄音查近,去河邊找鬼。 笑死勋颖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勋锤。 我是一名探鬼主播饭玲,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼叁执!你這毒婦竟也來了茄厘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤谈宛,失蹤者是張志新(化名)和其女友劉穎次哈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吆录,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窑滞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恢筝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哀卫。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖撬槽,靈堂內(nèi)的尸體忽然破棺而出此改,到底是詐尸還是另有隱情,我是刑警寧澤侄柔,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布共啃,位于F島的核電站占调,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏移剪。R本人自食惡果不足惜究珊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望挂滓。 院中可真熱鬧苦银,春花似錦、人聲如沸赶站。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贝椿。三九已至想括,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烙博,已是汗流浹背瑟蜈。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渣窜,地道東北人铺根。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乔宿,于是被迫代替她去往敵國(guó)和親位迂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容