mininet编程实现交换机规则的插入、删除与修改。_Mysql事务隔离以及MVCC实现原理...
????????上一篇我們了解了mysql的幾種日志,大致知道這些日志的作用,今天我們配合Mysql的事務(wù)以及事務(wù)的隔離級別進(jìn)一步理解mysql如何實現(xiàn)事務(wù)相關(guān)的特性。其中重點理解mysql innodb的多版本控制和樂觀鎖,這篇大部分是文字描述,也是理解mysql-innodb事務(wù)的基礎(chǔ)內(nèi)容,也是面試會問到的內(nèi)容。
事務(wù)的特征ACID
原子性:事務(wù)是一個原子操作單元,其對數(shù)據(jù)的修改,要么全都執(zhí)行,要么全都不執(zhí)行。上一篇我們知道 redo log 用于保證事務(wù)持久性,是因為每次數(shù)據(jù)變更,mysql都會先記錄redo log,然后更新到數(shù)據(jù)頁的緩存,然后在刷到磁盤中;那mysql是如何實現(xiàn)原子性的呢,首先理解原子性,就是一組操作單元,要么全部執(zhí)行成功,要么不執(zhí)行,我們在做分布式的系統(tǒng)的時候,就會涉及到分布式的事務(wù),兩個分布式操作,要么都成功,要么都失敗,所有的操作都需要回滾到最初的狀態(tài),我們所了解有XA協(xié)議規(guī)則,XA是比較老的分布式事務(wù)基礎(chǔ),它的核心思路是基于兩階段提交的方式,第一階段,數(shù)據(jù)準(zhǔn)備,然后鎖住資源,第二步才會提交。今天我們不討論分布式事務(wù)的方案,這里不做深入研究,大家可以了解一下兩階段和TCC三階段,以及Base定理和CAP定理。好了,言歸正傳,我們從工作中的場景,來反向思考,mysql的事務(wù)是如何實現(xiàn)的呢?對于一個事務(wù)如何保證這些語句最終能保證原子性呢?上一篇講到了redolog 和binlog的一致性方案,就涉及到兩階段提交的方式來保證一致性。這里要講的是Mysql的undo log,它是保證事務(wù)的原子性和隔離性的基礎(chǔ)。
我們知道m(xù)ysql事務(wù)中只要對數(shù)據(jù)修改的,都會生成相應(yīng)的undo日志,1.對于每個 insert,這會往undo日志插入一條對應(yīng)的刪除語句,回滾時會執(zhí)行 delete2.對于每個 delete,回滾時會執(zhí)行 insert。3.對于每個 update,回滾時會執(zhí)行一個相反的 update,把數(shù)據(jù)改回去。以 update 操作為例:當(dāng)事務(wù)執(zhí)行 update 時,其生成的 undo log 中會包含被修改行的主鍵(以便知道修改了哪些行)、修改了哪些列、這些列在修改前后的值等信息,回滾時便可以使用這些信息將數(shù)據(jù)還原到 update 之前的狀態(tài)。
一致性:在事務(wù)開始和完成時,數(shù)據(jù)都必須保持一致狀態(tài),保持?jǐn)?shù)據(jù)的完整性。其實這里說的一致性,如果原子性保證了,mysql的數(shù)據(jù)庫的數(shù)據(jù)就會更新成功,失敗則回滾到原來的狀態(tài),所以一致性其實是基于事務(wù)的原子性和持久性下,一致性就自然而然就得到了保證。
1.事務(wù)執(zhí)行成功,redo日志和binlog日志就是持久性保障2.事務(wù)執(zhí)行失敗則, undo log則是事務(wù)原子性的保障,他擔(dān)負(fù)這回滾的任務(wù)。
隔離性:數(shù)據(jù)庫系統(tǒng)提供一定的隔離機制,保證事務(wù)在不受外部并發(fā)操作影響的“獨立”環(huán)境執(zhí)行。隔離性則是多事務(wù)并行操作下,保證各個事務(wù)之間獨立運行相互隔離的,不受其他事務(wù)影響的特性。持久性:事務(wù)完成之后,它對于數(shù)據(jù)的修改是永久性的,它是原子性和一致性保證的前提下。
數(shù)據(jù)庫隔離級別
????????Mysql-innodb可以通過設(shè)置mysql的事務(wù)隔離級別,全局修改,修改mysql.ini配置文件,在最后加上transaction-isolation = REPEATABLE-READ,#可選參數(shù)有:讀未提交READ-UNCOMMITTED,讀已提交:READ-COMMITTED, 可重復(fù)讀:REPEATABLE-READ, 串行化:SERIALIZABLE
1.讀未提交:就是在并發(fā)事務(wù)中,可以讀到?jīng)]有提交的事務(wù)變更數(shù)據(jù);2.讀已提交:讀到已經(jīng)提交的事務(wù)變更記錄;3.可重復(fù)讀:mysql的innodb默認(rèn)的事務(wù)隔離級別,每次查詢一條記錄的時候,每個事務(wù)都會創(chuàng)建不同的讀視圖read-view,所以在該事務(wù)下,都會讀對應(yīng)的視圖,如果有三個事務(wù),每一個事務(wù)都有自己讀到的最新數(shù)據(jù)的視圖,所以在事務(wù)中,每次讀到的都是一開始數(shù)據(jù)的快照版本,這就是mysql的多版本并發(fā)控制,下面會詳細(xì)介紹mysql的MVCC。4.串行化:是最高的事務(wù)隔離級別,沒開啟一個事務(wù),都是串行的,每一個事務(wù)都會對相應(yīng)的數(shù)據(jù)行加鎖來保證串行,這樣一個事務(wù)結(jié)束,才能開啟下一個事務(wù),這樣就完全保證了事務(wù)直接的隔離性。一般情況下并不會設(shè)置該隔離級別。
為什么要有可重讀的隔離級別
????????我們知道數(shù)據(jù)庫操作的時候,它是不斷更新的,如果說我一個事務(wù),開始執(zhí)行的時候,我只想用到當(dāng)前已有記錄,不管是否已經(jīng)更新,或者追加 或者減少,我都希望我當(dāng)前操作是我事務(wù)開始的快照,不管是否發(fā)生變化,這樣,可重復(fù)讀就可以滿足我們的需求,不管我是查詢,還是更新,刪除 已提交的事務(wù),我都不喜歡看到原來的數(shù)據(jù)有變化。這就是實際開發(fā)中,我們?yōu)榱朔乐钩霈F(xiàn)幻讀的情況。
可重復(fù)讀的實現(xiàn)
????????上面說了,可重復(fù)讀隔離級別下,數(shù)據(jù)庫會為我們創(chuàng)建相應(yīng)的read-view快照,事務(wù)中的所有操作都會基于這個快照版本。還有mysql實現(xiàn)了MVCC的并發(fā)訪問控制的機制,那么什么是MVCC呢?首先這里我選擇直接查看官方文檔,這樣理解起來是最原始的資料,以免自己陷入不同的blog解說版本,可能不利于自己分析問題。
[Mysql5.5官方開發(fā)文檔中MVCC解釋]
1.介紹
??????? nnoDB是一個多版本存儲引擎:它保存有關(guān)已更改行的舊版本的信息,以支持并發(fā)和回滾等事務(wù)功能。此信息存儲在表空間中稱為回滾段的數(shù)據(jù)結(jié)構(gòu)中(在Oracle中的類似數(shù)據(jù)結(jié)構(gòu)之后)。InnoDB使用回滾段中的信息來執(zhí)行事務(wù)回滾中所需的撤消操作。 它還使用該信息構(gòu)建行的早期版本以進(jìn)行一致讀取。
2.MVCC多版本的實現(xiàn)方案
??????? InnoDB為存儲在數(shù)據(jù)庫中的每一行添加三個字段。6字節(jié)的DB_TRX_ID字段指示插入或更新該行的最后一個事務(wù)的事務(wù)標(biāo)識符 。此外,刪除在內(nèi)部被視為更新,其中行中的特殊位被設(shè)置為將其標(biāo)記為已刪除 每行還包含一個7字節(jié)的DB_ROLL_PTR字段,稱為滾動指針。 roll指針指向?qū)懭牖貪L段的撤消日志記錄。如果更新了行,則撤消日志記錄包含在更新行之前重建行內(nèi)容所需的信息。6字節(jié)的DB_ROW_ID字段包含在插入新行時單調(diào)增加的行ID。 如果InnoDB自動生成聚簇索引,則索引包含行ID值。否則,DB_ROW_ID列不會出現(xiàn)在任何索引中。
DATA_TRX_ID 標(biāo)記了最新更新這條行記錄的transaction id,每處理一個事務(wù),其值自動+1DATA_ROLL_PTR 指向當(dāng)前記錄項的rollback segment的undo log記錄,找之前版本的數(shù)據(jù)就是通過這個指針DB_ROW_ID,當(dāng)由innodb自動產(chǎn)生聚集索引時,聚集索引包括這個DB_ROW_ID的值,否則聚集索引中不包括這個值.,這個用于索引當(dāng)中DELETE BIT位用于標(biāo)識該記錄是否被刪除,這里的不是真正的刪除數(shù)據(jù),而是標(biāo)志出來的刪除。真正意義的刪除是在commit的時候。這個字段 在官方文檔中沒有,但是很多博客中有出現(xiàn),可能是在5.5之后的版本才加上的。
3.undo日志如何產(chǎn)生和銷毀:
????????回滾段中的undo log分為插入和更新撤消日志。 只在事務(wù)回滾中才需要插入undo日志,并且可以在事務(wù)提交后立即丟棄。更新undo log也用于一致性讀取,但只有在InnoDB沒有分配快照的事務(wù)之后才能丟棄它們,在一致讀取中可能需要更新撤消日志中的信息來構(gòu)建早期版本的 數(shù)據(jù)庫行。
4.長事務(wù)問題
????????按時提交你的事務(wù),包括那些只發(fā)出一致讀取的事務(wù)。 否則,InnoDB無法丟棄更新撤消日志中的數(shù)據(jù),并且回滾段可能會變得太大,從而填滿了表空間?;貪L段中撤消日志記錄的物理大小通常小于相應(yīng)的插入或更新行。 您可以使用此信息計算回滾段所需的空間。這個問題,也就說明了我們盡量不要使用長事務(wù),長時間不提交,導(dǎo)致回滾段日志變得很大,導(dǎo)致mysql數(shù)據(jù)庫不可用。
5.刪除記錄時,MVCC的實現(xiàn)機制
????????在InnoDB多版本控制方案中,當(dāng)您使用SQL語句刪除行時,不會立即從數(shù)據(jù)庫中物理刪除該行。InnoDB在丟棄為刪除寫入的更新undo log記錄時,僅物理刪除相應(yīng)的行及其索引記錄。此刪除操作稱為清除,并且速度非???#xff0c;通常與執(zhí)行刪除的SQL語句的時間順序相同。
高性能Mysql
????????下面是《高性能Mysql》中尋找一下MVCC的相關(guān)解釋,發(fā)現(xiàn)和官方版本就是并不一致,它是以更加簡化的思路來闡述MVCC的版本控制,我們也可以解讀一下。
1.mvcc是行級鎖的一個變種,它為了避免直接加鎖,性能更好,2.實現(xiàn)是通過保存數(shù)據(jù)某個時間點的快照3.innodb中的MVCC通過在每行的記錄后面保存兩個隱藏的列來實現(xiàn)的,(1).一個是保存創(chuàng)建行的系統(tǒng)創(chuàng)建版本號,每開啟一個事務(wù),該版本號就會自增,這系統(tǒng)版本號作為事務(wù)的版本號,用來查詢和定位多事務(wù)的隔離版本(2).另一個字段就是行的過期時間或者刪除時間。備注:這里隱藏的列其實和官方開發(fā)文檔dev中的描述有相似的地方,作者這里只是簡單描述MVCC的工作原理,所以具體的我們還是以官方文檔為準(zhǔn)。4.MVCC只會在可重復(fù)讀和讀提交的隔離級別下工作,因為讀未提交的數(shù)據(jù)就是讀的最新的數(shù)據(jù)行,串行化是通過加鎖。
樂觀鎖和MVCC 是一件事嗎?
????????通過上面的分析,我們是否有一種錯覺,MVCC不就是實現(xiàn)的樂觀鎖的功能嗎,我們是不是開發(fā)的時候不需要再考慮Mysql的樂觀鎖問題。一般的我們在并發(fā)中,涉及到更新操作時,都會再where條件加上對應(yīng)的版本信息(比如時間戳,具體的變更字段狀態(tài)等),這里最好還是使用時間戳,比較好,因為我們系統(tǒng)數(shù)據(jù)設(shè)計的時候都會有modifyDate字段,狀態(tài)或者其他值,可能存在ABA問題,當(dāng)然幾率很小。這就是我們樂觀鎖的實現(xiàn)。上面說到MVCC,每次事務(wù)都會有MVCC保證可重復(fù)讀,并且有隱藏的版本控制,我們是不是就可以不用樂觀鎖了呢?這里,我有必要說一下,雖然MVCC有樂觀并發(fā)控制的意思,它只是控制了事務(wù)中該記錄的版本,然后事務(wù)讀到始終是快照版本而已,并沒有做事務(wù)提交時版本的判斷,所以我們還是要手動的進(jìn)行樂觀鎖的判斷。并且拿到更新int結(jié)果為1,或者是預(yù)期值時才認(rèn)為更新成功,否則需要做回滾。
小結(jié)
????????今天學(xué)習(xí)了mysql的ACID的實現(xiàn)原理,和事務(wù)隔離級別中的可重復(fù)讀的實現(xiàn)機制MVCC,加深了事務(wù)的理解,如果上述闡述的有問題,或者不對的地方,歡迎留言指正和討論。
微信公眾號:MyClass社區(qū)
如有問題或建議,請公眾號留言。
喜歡請關(guān)注
總結(jié)
以上是生活随笔為你收集整理的mininet编程实现交换机规则的插入、删除与修改。_Mysql事务隔离以及MVCC实现原理...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: maxwell中文汉化补丁_《我的世界:
- 下一篇: python创建线程_多种方法实现 py