數(shù)據(jù)庫事務(wù)實現(xiàn)原理

01?概述

????事務(wù)一般是指數(shù)據(jù)庫事務(wù),簡稱事務(wù),是一組不可分割的操作。

????事務(wù)會把數(shù)據(jù)庫從一種一致狀態(tài)轉(zhuǎn)換為另一種一致狀態(tài)。在數(shù)據(jù)庫提交工作時,可以保證要么所有修改都保存了,要么所有修改都不保存(事務(wù)是數(shù)據(jù)庫區(qū)別于文件系統(tǒng)的重要特征之一)。

? ??說明:

????1、每個SQL語句都是一個事務(wù);

????2、事務(wù)只對DML語句有效,對于DQL無效。

????用轉(zhuǎn)賬的例子來說,A 賬戶要給 B 賬戶轉(zhuǎn) 100塊,這中間至少包含了兩個操作:

????1、A 賬戶減100塊

????2、B 賬戶加100塊

????在支持事務(wù)的數(shù)據(jù)庫管理系統(tǒng)來說,就是得確保上面兩個操作都能完成,不能存在,A的100塊扣了,然后B的賬戶又沒加上去的情況。

02?分類

2.1 扁平事務(wù)

????在扁平事務(wù)中,所有操作都處于同一層次,其由BEGIN WORK開始,由COMMIT WORK或ROLLBACK WORK結(jié)束,其間的操作是原子的,要么都執(zhí)行,要么都回滾。因此,扁平事務(wù)是應(yīng)用程序成為原子操作的基本組成模塊。

????扁平事務(wù)的主要限制是不能提交或者回滾事務(wù)的某一部分,或分幾個步驟提交。因此就出現(xiàn)了帶有保存點的扁平事務(wù)。

2.2 帶有保存點的扁平事務(wù)

????帶有保存點的扁平事務(wù)(Flat Transaction with Savepoint),除了支持扁平事務(wù)支持的操作外,允許在事務(wù)執(zhí)行過程中回滾到同一事務(wù)中較早的一個狀態(tài)。這是因為某些事物可能在執(zhí)行過程中出現(xiàn)的錯誤并不會導(dǎo)致所有的操作都無效,放棄整個事務(wù)不合乎要求,開銷也太大。

2.3 鏈事務(wù)

????鏈事務(wù)(Chained Transaction)可視為保存點模式的一種變種。帶有保存點的扁平事務(wù),當發(fā)生系統(tǒng)崩潰時,所有的保存點都將消失,因為其保存點是易失的(volatile),而非持久的(persistent)。這意味著當進行恢復(fù)時,事務(wù)需要從開始處重新執(zhí)行,而不能從最近的一個保存點繼續(xù)執(zhí)行。

????鏈事務(wù)的思想是:在提交一個事務(wù)時,釋放不需要的數(shù)據(jù)對象,將必要的處理上下文隱式地傳給下一個要開始的事務(wù)。注意,提交事務(wù)操作和開始下一個事務(wù)操作將合并為一個原子操作。這意味著下一個事務(wù)看到上一個事務(wù)的結(jié)果,就好像在一個事務(wù)中進行的一樣。

????鏈事務(wù)與帶有保存點的扁平事務(wù)不同的是,帶有保存點的扁平事務(wù)能夠回滾到任意正確的保存點。而鏈事務(wù)中的回滾僅限于當前事務(wù),即只能恢復(fù)到最近一個的保存點。對于鎖的處理,二者也不相同。鏈事務(wù)在執(zhí)行COMMIT后即釋放當前事務(wù)所持有的鎖,而帶有保存點的扁平事務(wù)不影響迄今為止所持有的鎖。

2.4 嵌套事務(wù)

????嵌套事務(wù)(Nested Transaction)是一個層次結(jié)構(gòu)框架。由一個頂層事務(wù)(top-level transaction)控制著各個層次的事務(wù)。頂層事務(wù)之下嵌套的事務(wù)被稱為子事務(wù)(subtransaction),其控制每一個局部的變換。

2.5 分布式事務(wù)

????分布式事務(wù)(Distributed Transaction)通常是一個在分布式環(huán)境下運行的扁平事務(wù),因此需要根據(jù)數(shù)據(jù)所在位置訪問網(wǎng)絡(luò)中的不同節(jié)點。

03?ACID

????一個支持事務(wù)(Transaction)的數(shù)據(jù)庫,必須要具有ACID這四種特性,否則在事務(wù)過程當中無法保證數(shù)據(jù)的正確性,交易過程極可能達不到交易方的要求。

????注:在單機環(huán)境下,事務(wù)遵循ACID特性,但是在分布式事務(wù)中,ACID已經(jīng)不能保證事務(wù)的有效性,還需要遵循CAP和BASE理論。

3.1原子性(Atomicity)

????整個事務(wù)中所有操作,要么全部完成,要么全部不完成,不可能停滯在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾(rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。

? ??原子性實現(xiàn):undo log

3.2?一致性(Consistency)

????事務(wù)必須始終保持系統(tǒng)處于一致的狀態(tài),不管在任何給定的時間并發(fā)事務(wù)有多少。

????在事務(wù)的四個特點中,一致性是事務(wù)的根本追求,而在某些情況下會對一致性造成破壞:

????1、事務(wù)的并發(fā)執(zhí)行

????2、事務(wù)故障或系統(tǒng)故障

????數(shù)據(jù)庫系統(tǒng)通過并發(fā)控制技術(shù)和日志恢復(fù)技術(shù)來避免這種情況的發(fā)生:

????1、并發(fā)控制技術(shù)(加鎖+無鎖MVCC)保證了事務(wù)的隔離性,使數(shù)據(jù)庫的一致性狀態(tài)不會因為并發(fā)執(zhí)行的操作被破壞;

??? 2、日志恢復(fù)技術(shù)保證了事務(wù)的原子性,使一致性狀態(tài)不會因事務(wù)或系統(tǒng)故障被破壞。同時使已提交的數(shù)據(jù)庫的修改不會因系統(tǒng)崩潰而丟失,保證了事務(wù)的持久性。

????實現(xiàn)機制:原子性,隔離性,持久性

3.3 隔離性(Isolation)

????隔離狀態(tài)執(zhí)行事務(wù),使他們好像是系統(tǒng)在給定時間內(nèi)執(zhí)行的唯一操作。如果有兩個事務(wù),運行在相同的時間內(nèi),執(zhí)行相同的功能,事務(wù)的隔離性將確保每一個事務(wù)在系統(tǒng)中認為只有該事務(wù)在使用系統(tǒng)。這種屬性有時稱為串行化,為了防止事務(wù)操作間的混淆,必須串行化或者序列化請求,使得在同一時間僅有一個請求用于同一數(shù)據(jù)。

????實現(xiàn)機制:讀寫鎖+MVCC(不加鎖)

3.4 持久性(Durability)

???在事務(wù)完成以后,該事務(wù)對數(shù)據(jù)庫所作的變更會持久地保存在數(shù)據(jù)庫之中,并不會被回滾。

? ??實現(xiàn)機制:redo log重做日志

04?原理

4.1 回滾日志(undo)

? ? undo log屬于邏輯日志,它記錄的是sql執(zhí)行相關(guān)的信息。當發(fā)生回滾時,InnoDB會根據(jù)undo log的內(nèi)容做與之前相反的工作:對于每個insert,回滾時會執(zhí)行delete;對于每個delete,回滾時會執(zhí)行insert;對于每個update,回滾時會執(zhí)行一個相反的update,把數(shù)據(jù)改回去。

??? undo log用于存放數(shù)據(jù)被修改前的值,如果修改出現(xiàn)異常,可以使用undo日志來實現(xiàn)回滾操作,保證事務(wù)的一致性。另外InnoDB MVCC事務(wù)特性也是基于undo日志實現(xiàn)的。

????因此,undo log有兩個作用:提供回滾和多個行版本控制(MVCC)

4.2 重做日志(redo)

????redo?log重做日志記錄的是新數(shù)據(jù)的備份,屬于物理日志。在事務(wù)提交前,只要將redo log持久化即可,不需要將數(shù)據(jù)持久化。當系統(tǒng)崩潰時,雖然數(shù)據(jù)沒有持久化,但是redo log已經(jīng)持久化。系統(tǒng)可以根據(jù)redo log的內(nèi)容,將所有數(shù)據(jù)恢復(fù)到最新的狀態(tài)。

??? redo log包括兩部分:一是內(nèi)存中的日志緩沖(redo log buffer),該部分日志是易失性的;二是磁盤上的重做日志文件(redo log file),該部分日志是持久的。

??MySQL中redo log刷新規(guī)則采用一種稱為Checkpoint的機制(利用LSN實現(xiàn)),為了確保安全性,又引入double write機制。

4.3 MVCC

??? MVCC(Multi-Version Concurrency Control)多版本并發(fā)控制,可以簡單地認為:MVCC就是行級鎖的一個變種(升級版)。

????事務(wù)的隔離級別就是通過鎖的機制來實現(xiàn),只不過隱藏了加鎖細節(jié)。

????在表鎖中我們讀寫是阻塞的,基于提升并發(fā)性能的考慮,MVCC一般讀寫是不阻塞的。

MySQL中MVCC是通過redo log版本鏈+一致性視圖Read-view實現(xiàn)的。

05?隔離級別

5.1 UR:Read uncommitted

????查詢時,讀取的數(shù)據(jù)中允許含有臟數(shù)據(jù),不檢查來自各存儲節(jié)點的數(shù)據(jù)是否活躍,即不檢查來自各個存儲節(jié)點的數(shù)據(jù)是否來自同一版本或同一時刻的副本數(shù)據(jù)。

????在該隔離級別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。

? ??讀未提交存在臟讀問題。

????讀取未提交的數(shù)據(jù),被稱之為臟讀(Dirty Read)。

5.2 CR:Read commited

????查詢時,讀取的數(shù)據(jù)中不允許包含臟數(shù)據(jù),檢查來自各存儲節(jié)點的數(shù)據(jù)不能為活躍狀態(tài),即檢查來自各存儲節(jié)點的數(shù)據(jù)必須為同一版本或同一時刻的副本數(shù)據(jù)。

????這是大多數(shù)數(shù)據(jù)庫系統(tǒng)的默認隔離級別(但是不是MySQL默認隔離級別)。

????已提交讀通過對數(shù)據(jù)的版本進行校驗解決了臟讀問題,但是已提交讀存在不可重復(fù)讀。

?不可重復(fù)讀(Nonrepeatable Read),同一select可能返回不同結(jié)果。

5.3 RR:Repetable read

????這是MySQL的默認事務(wù)隔離級別,它確保同一事務(wù)的多個實例在并發(fā)(多次)讀取數(shù)據(jù)時,會看到同樣的數(shù)據(jù)行。

????可重復(fù)讀通過兩種機制解決不可重復(fù)讀:間隙鎖(加鎖方式),MVCC(不加鎖方式)。

????可重復(fù)讀存在幻讀(Phantom?Read)。簡單地說,幻讀指當用戶讀取某一范圍的數(shù)據(jù)行時,另一個事務(wù)又在該范圍內(nèi)插入了新行,當用戶再讀取該范圍的數(shù)據(jù)行時,會發(fā)現(xiàn)有新的“幻影”行。

????上述是標準SQL規(guī)定的隔離級別及存在的問題,但是,在MySQL中可重復(fù)讀已經(jīng)解決了幻讀!

5.4?Serializable

????這是最高的隔離級別,它通過強制事務(wù)排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數(shù)據(jù)行上加上共享鎖。在這個級別,可能導(dǎo)致大量的超時現(xiàn)象和鎖競爭。

5.5 總結(jié)

06?事務(wù)控制語句

6.1 事務(wù)基本操作

????開啟事務(wù):starttransaction

????回滾事務(wù):rollback

????提交事務(wù):commit

????保存點:

????SAVEPOINT保存點名稱;

????ROLLBACK[WORK]TO[SAVEPOINT] 保存點名稱;

????RELEASESAVEPOINT保存點名稱;

6.2 設(shè)置自動提交

????通過指令SHOW VARIABLES LIKE ‘a(chǎn)utocommit’;查看是否開啟事務(wù)自動提交,默認是開啟的。

????把系統(tǒng)變量autocommit設(shè)置為OFF,即SET autocommit=OFF,這樣寫入的多條語句就算是屬于一個事務(wù)了,直到我們顯式地寫出COMMIT語句才把該事務(wù)提交,或者顯式的寫出ROLLBACK語句把這個事務(wù)回滾。

6.3 事務(wù)隔離級別設(shè)置

????查看事務(wù)隔離級別

????select@@global.tx_isolation.@@tx_isolations;

????設(shè)置事務(wù)隔離級別

????全局的:setglobal/sessiontransactionisolationlevelreadcommited;

????當前會話:select@@tx_isolation;

07?隱式提交

? ??當我們使用START TRANSACTION或者BEGIN語句開啟一個事務(wù),或者把系統(tǒng)變量autocommit的值設(shè)置為OFF時,事務(wù)就不會進行自動提交,但是如果我們輸入了某些語句之后就會悄悄地提交,就像是輸入了COMMIT語句一樣,這種因為某些特殊的語句而導(dǎo)致事務(wù)提交的情況稱為隱式提交,這些會導(dǎo)致事務(wù)隱式提交的語句包括:

??? 1、定義或修改數(shù)據(jù)庫對象的DDL。所謂的數(shù)據(jù)庫對象,指的就是數(shù)據(jù)庫、表、視圖、存儲過程等這些東西,當我們使用CREATE、ALTER、DROP等語句去修改這些所謂的數(shù)據(jù)庫對象時,就會隱式的提交前面語句所屬于的事務(wù);

????2、隱式使用或修改數(shù)據(jù)庫中的表:當我們使用ALTER?USER、CREATE?USER、DROP?USER、GRANT、RENAME?USER、SET?PASSWORD等語句時也會隱式的提交前邊語句所屬于的事務(wù);

??? 3、事務(wù)控制或關(guān)于鎖定的語句:

????當我們在一個事務(wù)還沒有提交或者回滾時就又使用START TRANSACTION或者BEGIN語句開啟了另一個事務(wù)時,就會隱式的提交上一個事務(wù)。

????或者當前的autocommit系統(tǒng)變量的值為OFF,我們手動把它調(diào)為ON時,也會隱式的提交前面語句所屬的事務(wù)。

????或者使用LOCK TABLES、UNLOCK TABLES等關(guān)于鎖定的語句也會隱式的提交前面語句所屬的事務(wù)。

????4、加載數(shù)據(jù)的語句:比如我們使用LOAD?DATA語句來批量往數(shù)據(jù)庫中導(dǎo)入數(shù)據(jù)時,也會隱式的提交前面語句所屬的事務(wù)。

????5、其他一些語句:使用ANALYSE?TABLE、CACHE?INDEX、CHECK?TABLE、FLUSH、LOAD?INDEXINTO?CACHE、OPTIMIZE?TABLE、REPAIR?TABLE、RESET等語句也會隱式的提交前面語句所屬的事務(wù)。

????常用的select、insert、update和delete命令,都不會強制提交事務(wù)。

08?事務(wù)使用建議

????1、盡量避免使用長事務(wù);

????2、關(guān)閉自動提交,自己控制事務(wù)的開啟和提交;

????3、不要在循環(huán)操作中反復(fù)執(zhí)行事務(wù)提交;

??? 4、不要自動提交事務(wù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容