自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL事務(wù)詳解

數(shù)據(jù)庫(kù) MySQL
MySQL的InnoDB存儲(chǔ)引擎支持扁平事務(wù)、帶有保存點(diǎn)的事務(wù)、鏈?zhǔn)聞?wù)、分布式事務(wù)。

什么是事務(wù)?

  • 事務(wù)是一個(gè)不可分割的工作單元,工作單元要么工作完成,要么什么也不做。
  • 從應(yīng)用層面來說一個(gè)事務(wù)對(duì)應(yīng)了一個(gè)完整的業(yè)務(wù)功能。
  • 從數(shù)據(jù)庫(kù)層面的來講事務(wù)就是由一批DML語句構(gòu)成。

事務(wù)的分類

MySQL的InnoDB存儲(chǔ)引擎支持扁平事務(wù)、帶有保存點(diǎn)的事務(wù)、鏈?zhǔn)聞?wù)、分布式事務(wù)。

  • 扁平事務(wù)(Flat Transactions)

扁平事務(wù)應(yīng)用最為廣泛,實(shí)現(xiàn)最為簡(jiǎn)單,扁平事務(wù)的所有操作都是在同一個(gè)層級(jí),這些操作要么全部成功,要么全部回滾,不能存在部分提交或者部分回滾的的場(chǎng)景。

扁平事務(wù)

  • 帶保存點(diǎn)的扁平事務(wù)(Flat Transactions with Sacepoint)

扁平事務(wù)的限制就在于不能部分回滾或者提交,而有的場(chǎng)景是這么做是代價(jià)非常大的。比如我們舉個(gè)例子:

我們玩生存類游戲,如果我們意外失敗就必須從出生地開始玩,那么這會(huì)是讓人崩潰的,我們希望有一個(gè)游戲存檔,如果游戲失敗我們可以從最近的一個(gè)存檔重新加載游戲。

帶保存點(diǎn)的扁平事務(wù)就是,除了支持扁平事務(wù)的操作外,允許事務(wù)執(zhí)行過程中回滾到該事務(wù)較早的一個(gè)狀態(tài),而這個(gè)較早的狀態(tài)就是保存點(diǎn)來記錄的。

帶保存點(diǎn)的扁平事務(wù)

  • 鏈?zhǔn)聞?wù)(Chained Transaction)

鏈?zhǔn)聞?wù)是一種保存點(diǎn)事務(wù)的變種,兩者的最大區(qū)別是,帶保存點(diǎn)的事務(wù)可以回滾到較早前的任意保存點(diǎn),而鏈?zhǔn)绞聞?wù)只能回滾到最近一個(gè)保存點(diǎn);帶保存點(diǎn)的事務(wù)因?yàn)樾枰貪L到任意保存點(diǎn),固其事務(wù)執(zhí)行期間所占用的資源是不會(huì)被釋放的,而鏈?zhǔn)聞?wù)則在執(zhí)行完成當(dāng)前節(jié)點(diǎn)后會(huì)釋放掉不需要的資源,并將下一個(gè)節(jié)點(diǎn)需要的資源隱士傳遞下去。鏈?zhǔn)聞?wù)可以參考Flink流式計(jì)算的Checkpoint機(jī)制,兩者非常的相似。

鏈?zhǔn)聞?wù)

  • 嵌套事務(wù)(Nested Transaction)

嵌套事務(wù)顧名思義,事務(wù)結(jié)構(gòu)看上去就像一棵樹,根節(jié)點(diǎn)就是一個(gè)頂層事務(wù),所有的葉子節(jié)點(diǎn)都是扁平事務(wù)(也就是說葉子節(jié)點(diǎn)才是真正干活兒的),事務(wù)的嵌套層級(jí)不受限制。子事務(wù)可以提交也可以回滾,但是其提交不會(huì)立即生效,只有在頂層事務(wù)提交之后所有子事務(wù)才會(huì)被真正的提交。

嵌套事務(wù)

  • 分布式事務(wù)(Distributed Transactions)

分布式事務(wù)是指一個(gè)在分布式環(huán)境下運(yùn)行的扁平事務(wù),在本章中主要介紹本地事務(wù),分布式事務(wù)我會(huì)在后續(xù)章節(jié)是介紹。

事務(wù)的ACID特性

  • A(Atomicity)原子性:整個(gè)事務(wù)操作是一個(gè)完整的不可分割的整體,只有事務(wù)中的所有操作都執(zhí)行成功,事務(wù)才算執(zhí)行成功,否則就要回滾到事務(wù)執(zhí)行前的狀態(tài),即要么全部都做,要么全都不做。

例如:轉(zhuǎn)賬場(chǎng)景,自己賬戶扣除轉(zhuǎn)賬額度與對(duì)方賬戶收到轉(zhuǎn)賬這兩個(gè)操作必須是原子的。

  • C(Consistency)一致性:事務(wù)將數(shù)據(jù)庫(kù)從一種狀態(tài)轉(zhuǎn)變?yōu)榱硪环N狀態(tài),在事務(wù)執(zhí)行前和事務(wù)執(zhí)行后,數(shù)據(jù)庫(kù)的完整性約束沒有被破壞。

例如:用戶表的用戶ID列有unique約束,即用戶ID不可重復(fù),如果事務(wù)執(zhí)行插入了一樣的用戶ID,那么就產(chǎn)生了不一致的狀態(tài)。

  • I(Isolation)隔離性:隔離性(又稱并發(fā)控制)非常好理解,就是兩個(gè)事務(wù)之間不能相互影響,即當(dāng)前事務(wù)提交之前所作出的修改對(duì)其他事務(wù)都不可見,上一章我們講到了MySQL鎖,它就可以起到控制并發(fā)的作用。
  • D(Durability)持久性:持久性是指事務(wù)一旦提交,其結(jié)果就是永久性的,即使是服務(wù)器宕機(jī),數(shù)據(jù)也必須能夠得到恢復(fù),除了硬件故障,數(shù)據(jù)物理損壞,否則必須保證事務(wù)執(zhí)行結(jié)果的永久性,也就是保證高可靠性(High Reliablility)。

事務(wù)如何實(shí)現(xiàn)

事務(wù)的原子性、一致性、持久性通過redo log與undo log來完成,事務(wù)的隔離性由鎖與MVCC來完成。

Redo log(重做日志)

Redo log是用來實(shí)現(xiàn)事務(wù)的持久性,為了更好的讀寫性能,InnoDB會(huì)將數(shù)據(jù)緩存在內(nèi)存中,對(duì)磁盤數(shù)據(jù)的修改也會(huì)落后于內(nèi)存,如果進(jìn)程或系統(tǒng)崩潰,則數(shù)據(jù)面臨丟失的風(fēng)險(xiǎn),這時(shí)重做日志就起到了保證數(shù)據(jù)的一致性與持久性作用。重做日志主要記錄了以頁為單位的數(shù)據(jù)修改信息,其結(jié)構(gòu)如下:

redo log 結(jié)構(gòu)

  • 重做日志在Buffer中是連續(xù)寫入的,Buffer中的數(shù)據(jù)會(huì)適時(shí)地刷新到物理文件中;
  • 文件順序?qū)懭?,每個(gè)事務(wù)的重做日志追加到文件末尾;
  • 單個(gè)文件大小固定,寫滿以后會(huì)切回到文件組的下一個(gè)文件;
  • 重做日志文件組的文件個(gè)數(shù)是固定的,寫完最后一個(gè)文件則繼續(xù)回到第一個(gè)文件開始寫入;
  • 每個(gè)重做文件有固定2K的文件頭,文件頭的之后是以一個(gè)個(gè)512bytes的Block,每個(gè)Block有16bytes的頭尾信息;
  • 重做日志有一個(gè)全局的日志序列號(hào)(LSN:Log Sequence Number),單調(diào)遞增,表示事務(wù)寫入的重做日志的字節(jié)總量,也就是一個(gè)日志偏移量。

Undo log(回滾日志)

重做日志記錄了事務(wù)的行為,可以在需要的時(shí)候?qū)撨M(jìn)行“重做”,但是事務(wù)有時(shí)是需要被回滾的,當(dāng)語句執(zhí)行失敗或者用戶請(qǐng)求回滾,就可以通過undo log將數(shù)據(jù)回滾到修改前的樣子,undo log是存儲(chǔ)了行記錄的變更。其主要包含兩類undo log:

兩種undo log結(jié)構(gòu)

  • insert undo log:insert操作時(shí)產(chǎn)生,只對(duì)當(dāng)前事務(wù)本身可見,在事務(wù)提交之后可直接刪除。
  • update undo log:delete與update操作產(chǎn)生,需要提供歷史版本,為后續(xù)章節(jié)要講到的MVCC服務(wù),其交由purge線程統(tǒng)一刪除。
  • undo log需要通過group commit 操作將數(shù)據(jù)fsync到磁盤,以保證事務(wù)的持久性。

下面是一個(gè)事務(wù)與undo log的關(guān)系結(jié)構(gòu):

事務(wù)與undo log關(guān)系結(jié)構(gòu)

事務(wù)隔離

事務(wù)在并發(fā)場(chǎng)景下很難保證事務(wù)的隔離性一致性,主要有以下一些事務(wù)的并發(fā)一致性問題。

事務(wù)并發(fā)問題

  • 臟讀(Dirty Read):事務(wù)A讀取了另外一個(gè)并行事務(wù)B未提交的數(shù)據(jù)。
  • 不可重復(fù)讀(Non-Repeatable Read:在解決臟讀問題之后,能夠保證讀事務(wù)讀取到的數(shù)據(jù)都是持久的數(shù)據(jù),如果事務(wù)A多次讀取同一數(shù)據(jù),正好在兩次讀取之間,另外一個(gè)并行事務(wù)B提交了這一數(shù)據(jù)的修改,這就導(dǎo)致事務(wù)A多次讀取到的同一數(shù)據(jù)內(nèi)容不一樣。
  • 幻讀(Phantom):與不可重復(fù)讀類似,事務(wù)A多次查詢一個(gè)范圍,另外一個(gè)并行事務(wù)B向該范圍內(nèi)插入或刪除了數(shù)據(jù)并提交,當(dāng)事務(wù)A再次查詢時(shí)發(fā)現(xiàn)記錄變多或者丟失。
  • 更新丟失(Lost Updates):兩個(gè)事務(wù)A和B修改了同一數(shù)據(jù),由于未提交事務(wù)之間看不到對(duì)方的修改,因此都以一個(gè)舊的前提去更新了同一數(shù)據(jù)。
  • 寫偏差(Write Skew):與更新丟失類似,都是寫前提被改變,寫偏差則是事務(wù)A讀取某些數(shù)據(jù),作為另一些寫入的前提條件(更新丟失是針對(duì)同一數(shù)據(jù)),但這時(shí)另外一個(gè)事務(wù)B對(duì)事務(wù)A已讀取的數(shù)據(jù)做了修改并提交,從而導(dǎo)致事務(wù)A做了錯(cuò)誤的commit操作。
  • 讀偏差(Read Skew):如事務(wù)A讀取某兩個(gè)數(shù)據(jù)求和,事務(wù)B在事務(wù)A讀取期間對(duì)已讀取數(shù)據(jù)做了增減,此時(shí)事務(wù)A求和得到的結(jié)果就會(huì)與實(shí)際的結(jié)果不一致。

針對(duì)上面的并發(fā)問題,InnoDB存儲(chǔ)引擎通過MVCC(當(dāng)然MVCC本質(zhì)上也是一種樂觀鎖)與鎖(關(guān)于鎖的介紹可以閱讀我的上一篇文章)來解決事務(wù)的隔離性一致性問題。

事務(wù)隔離級(jí)別

事務(wù)隔離級(jí)別是MySQL對(duì)ACID的實(shí)現(xiàn)程度上的分級(jí),分為了四個(gè)等級(jí),等級(jí)越高數(shù)據(jù)庫(kù)越安全,每種隔離級(jí)別解決了不同事務(wù)并發(fā)一致性的問題,具體如下:

  • READ UNCOMMITTED(讀未提交):這是一個(gè)最差的隔離級(jí)別,該級(jí)別下事務(wù)可以讀到其它事務(wù)未提交的數(shù)據(jù),也就是說在該事務(wù)隔離級(jí)別下會(huì)發(fā)生上述的所有并發(fā)一致性問題。
  • READ COMMITTED(讀已提交):事務(wù)只能讀取到已提交的修改,也就是說多個(gè)并發(fā)的事務(wù)之間的修改是相互不可見的,該事務(wù)隔離級(jí)別解決了臟讀問題。
  • REPEATABLE READ(可重復(fù)讀):該級(jí)別保證同一個(gè)事務(wù)中多次讀取同一數(shù)據(jù)的結(jié)果是一致的,該級(jí)別是InnoDB默認(rèn)的隔離級(jí)別,該隔離級(jí)別解決了臟讀與不可重復(fù)讀問題,但是仍可能出現(xiàn)幻讀的情況(InnoDB存儲(chǔ)引擎在該隔離級(jí)別下使用了Next-Key Lock解決了幻讀問題)。
  • SERIALIZABLE(串行化):強(qiáng)制事務(wù)串行化執(zhí)行,沒有并發(fā),那么并發(fā)問題自然就不存在了,當(dāng)然在該級(jí)別下的事務(wù)性能非常低。

關(guān)于事務(wù)隔離的實(shí)現(xiàn)會(huì)在后續(xù)文章詳細(xì)講解,本文不在展開。

事務(wù)的執(zhí)行過程

事務(wù)的執(zhí)行過程

  • 查詢數(shù)據(jù),若數(shù)據(jù)不存在于buffer,則從磁盤加載;
  • 數(shù)據(jù)更新前,先將當(dāng)前數(shù)據(jù)記錄到undo log重,以便后續(xù)可能出現(xiàn)的回滾做準(zhǔn)備;
  • 更新Buffer Pool中的數(shù)據(jù);
  • 將更新的數(shù)據(jù)寫入到Redo Log Buffer中;
  • 準(zhǔn)備提交事務(wù),調(diào)用fsync將Redo Log Buffer的數(shù)據(jù)寫入到redo log文件中,狀態(tài)記為prepared;
  • 準(zhǔn)備提交事務(wù),binlog寫入到磁盤中;
  • binlog寫入成功后,將redo log的狀態(tài)更新為commit;

binlog的開啟時(shí)會(huì)存在一個(gè)內(nèi)部XA的問題(binlog是在MySQL層,而redo log在存儲(chǔ)引擎層),這里引入了2PC(二階段提交):

  • prepare階段:redo log持久化到磁盤,同時(shí)設(shè)置狀態(tài)為prepared,binlog此時(shí)不錯(cuò)任何操作。
  • commit階段:存儲(chǔ)引擎釋放鎖,是否回滾段,然后binlog持久化到磁盤,然后存儲(chǔ)引擎層提交,更改redo log的狀態(tài)為commit。
責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2024-12-02 08:37:04

2023-06-25 08:05:09

MySQL事務(wù)并發(fā)

2010-11-19 16:13:06

oracle事務(wù)隔離級(jí)

2020-09-21 18:44:35

MySQL

2024-03-15 11:59:25

SQL數(shù)據(jù)庫(kù)ACID

2024-11-13 19:03:14

2022-05-20 10:20:17

Spring事務(wù)MyBatis

2009-06-08 17:56:00

SpringJDBC事務(wù)

2023-03-27 10:40:09

2023-09-27 16:22:51

SpringMySQL原子性

2010-11-22 16:40:00

MySQL事務(wù)表

2010-06-18 10:58:28

UML模型元素

2022-07-10 20:24:48

Seata分布式事務(wù)

2011-08-12 13:33:31

Oracle數(shù)據(jù)庫(kù)自治事務(wù)

2021-07-13 07:31:26

Springboot編程事務(wù)管理

2018-12-19 16:46:38

MySQL事務(wù)隔離數(shù)據(jù)庫(kù)

2010-10-11 09:25:06

定義MySQL事務(wù)

2020-06-17 16:56:36

數(shù)據(jù)庫(kù)MySQL跨行事務(wù)

2017-08-22 17:10:45

數(shù)據(jù)庫(kù)MySQL事務(wù)模型

2024-06-13 09:25:14

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)