成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【深入淺出事務(wù)】(3):事務(wù)的隔離級別(超詳細)

zhangrxiang / 2952人閱讀

摘要:客戶端設(shè)置手動提交,修改事務(wù)隔離級別為,并且開啟事務(wù)一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交。

本質(zhì)

隔離級別定義了數(shù)據(jù)庫系統(tǒng)中一個操作產(chǎn)生的影響什么時候以哪種方式可以對其他并發(fā)操作可見,隔離性是事務(wù)的ACID中的一個重要屬性,核心是對鎖的操作。

從數(shù)據(jù)庫系統(tǒng)角度

共享鎖(Shared Lock)

讀鎖,保證數(shù)據(jù)只能讀取,不能被修改。
如果事務(wù)A對數(shù)據(jù)M加上S鎖,則事務(wù)A可以讀記錄M但不能修改記錄M,其他事務(wù)(這里用事務(wù)B)只能對記錄M再加上S鎖,不能加X鎖,直到事務(wù)A釋放了記錄M上的S鎖,保證了其他事務(wù)(事務(wù)B)可以讀記錄M,但在事務(wù)A釋放M上的S鎖之前不能對記錄M進行任何修改。

例子: MySql 5.5 證明S鎖的特性。

數(shù)據(jù)準備

CREATE TABLE `test1` (`id`  bigint(1) NOT NULL DEFAULT 0 ,`name`  varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,PRIMARY KEY (`id`))
INSERT INTO test1 VALUES(1,1),(2,2),(3,3)

設(shè)置事務(wù)為手動提交,方便證明上訴結(jié)論(mysql默認為自動提交,執(zhí)行單句sql其實包含 開啟事務(wù),執(zhí)行sql,提交事務(wù),3個步驟)。

客戶端A開啟一個事務(wù)A。

客戶端A給test1表加上讀鎖。

查詢test1表原有的數(shù)據(jù)(加上S鎖后,可以讀數(shù)據(jù))。

事務(wù)A修改數(shù)據(jù)(加上S鎖后,無法修改數(shù)據(jù))。

B客戶端開啟事務(wù)B。

事務(wù)B對記錄M查詢(因為是S鎖,其他事務(wù)可以對記錄A進行select )。

事務(wù)B對記錄M加讀鎖(事務(wù)A對記錄A加上S鎖后,事務(wù)B同樣也可以對記錄A加上S鎖,證明了,mysql里的讀鎖就是S鎖,具有共享)。

事務(wù)B對記錄M加寫鎖(一直處于等待狀態(tài),被掛起,具體掛起的原因可以見:Innodb行鎖源碼學習。

事務(wù)B對記錄M修改(一直處于等待狀態(tài),被掛起)。

事務(wù)A釋放M上的S鎖。

此時事務(wù)B才得到響應(yīng)。

說明了,只有釋放了讀鎖,另外一個事務(wù)才能加寫鎖,或者更新數(shù)據(jù)。

排他鎖(X 鎖)

寫鎖,若事務(wù)A對數(shù)據(jù)對象M加上X鎖,事務(wù)A可以讀記錄M也可以修改記錄M,其他事務(wù)(事務(wù)B)不能再對記錄M加任何鎖,直到事務(wù)A釋放記錄M上的鎖,保證了其他事務(wù)(事務(wù)B)在事務(wù)A釋放記錄M上的鎖之前不能再讀取和修改記錄M。

例子:Mysql 5.5,證明X鎖的特性。

客戶端A設(shè)置手動提交,并且開啟事務(wù)A。

客戶端B設(shè)置手動提交,并且開啟事務(wù)B。

事務(wù)A給記錄M加上X鎖。

事務(wù)A可以讀記錄M也可以修改記錄M。

事務(wù)B不能對記錄M加任何鎖。

事務(wù)B也不能對記錄M進行查詢和修改。

事務(wù)A釋放記錄M上的X鎖。

事務(wù)B阻塞的進程被執(zhí)行,中斷了6秒。

從程序員角度

悲觀鎖(Pessimistic[?pes??m?st?k] Lock)

對數(shù)據(jù)被外界修改保持保守態(tài)度,在整個數(shù)據(jù)處理過程中,數(shù)據(jù)處于鎖定狀態(tài),依賴于數(shù)據(jù)庫提供的鎖機制。

樂觀鎖(Optimistic[?ɑ:pt??m?st?k]Lock)

采用寬松的加鎖機制,基于數(shù)據(jù)版本記錄機制,具體做法:數(shù)據(jù)庫表增加一個"version"字段來實現(xiàn),讀取數(shù)據(jù)時,將版本號一同讀出,之后更新,對版本號加1,將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫對應(yīng)記錄的當前版本信息進行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫的數(shù)據(jù),則予以更新,否則,被認為是過期數(shù)據(jù)。

幾個概念 丟失更新

事務(wù)A和事務(wù)B,同時獲得相同數(shù)據(jù),然后在各自的事務(wù)中修改數(shù)據(jù)M,事務(wù)A先提交事務(wù),數(shù)據(jù)M假如為M+,事務(wù)B后提交事務(wù),數(shù)據(jù)M變成了M++,最終結(jié)果變成M++,覆蓋了事務(wù)A的更新。

例子:

事務(wù)A 事務(wù)B
讀取X=100 讀取X=100
寫入X=X+100
事務(wù)結(jié)束X=200
寫入X=X+100
事務(wù)結(jié)束X=300(事務(wù)A的更新丟失)
臟讀

允許事務(wù)B可以讀到事務(wù)A修改而未提交的數(shù)據(jù),可能會造成了臟讀(臟讀本質(zhì)就是無效的數(shù)據(jù),只有當事務(wù)A回滾,那么事務(wù)B讀到的數(shù)據(jù)才為無效的,所以這里只是可能造成臟讀,當事務(wù)A不回滾的時候,事務(wù)B讀到的數(shù)據(jù)就不為臟數(shù)據(jù),也就是有效的數(shù)據(jù),臟數(shù)據(jù)會導致以后的操作都會發(fā)生錯誤,一定要去避免,不能憑借僥幸,事務(wù)A不能百分之百保證不回滾,所以這種隔離級別很少用于實際應(yīng)用,并且它的性能也不比其他級別好多少)。

例子:

事務(wù)A 事務(wù)B
寫入X=X+100(x=200)
讀取X=200(無效數(shù)據(jù),臟讀)
事務(wù)回滾X=100
事務(wù)結(jié)束X=100
事務(wù)結(jié)束
不可重復讀

不可重復讀是指在一個事務(wù)范圍中2次或者多次查詢同一數(shù)據(jù)M返回了不同的數(shù)據(jù),例如:事務(wù)B讀取某一數(shù)據(jù),事務(wù)A修改了該數(shù)據(jù)M并且提交,事務(wù)B又讀取該數(shù)據(jù)M(可能是再次校驗),在同一個事務(wù)B中,讀取同一個數(shù)據(jù)M的結(jié)果集不同,這個很蛋疼。

例子:

事務(wù)A 事務(wù)B
讀取X=100 讀取X=100
寫入X=X+100 讀取X=100
事務(wù)結(jié)束,X=200
讀取X=200(在一個事務(wù)B中讀X的值發(fā)生了變化)
事務(wù)結(jié)束
幻讀

當用戶讀取某一個范圍的數(shù)據(jù)行時,另一個事務(wù)又在該范圍內(nèi)查詢了新行,當用戶再讀取該范圍的數(shù)據(jù)行時,會發(fā)現(xiàn)會有新的“幻影行”,例如:事務(wù)B讀某一個數(shù)據(jù)M,事務(wù)A對數(shù)據(jù)M增加了一行并提交,事務(wù)B又讀數(shù)據(jù)M,發(fā)生多出了一行造成的結(jié)果不一致(如果行數(shù)相同,則是不可重復讀)。

例子:

事務(wù)A 事務(wù)B
讀取數(shù)據(jù)集M(3行)
在數(shù)據(jù)集M插入一行(4行)
事務(wù)結(jié)束
讀取數(shù)據(jù)M(4行)
事務(wù)結(jié)束

在事務(wù)B里,同一個數(shù)據(jù)集M,讀到的條數(shù)不一致(新增,刪除)。

封鎖協(xié)議

在運用S鎖和X鎖對數(shù)據(jù)M加鎖的時候,需要約定一些規(guī)則,例如何時申請S鎖或者X鎖,持鎖時間,這些規(guī)則就是封鎖協(xié)議。
其中不同的封鎖協(xié)議對應(yīng)不同的隔離級別。

一級封鎖協(xié)議

一級封鎖協(xié)議對應(yīng)READ-UNCOMMITTED 隔離級別,本質(zhì)是在事務(wù)A中修改完數(shù)據(jù)M后,立刻對這個數(shù)據(jù)M加上共享鎖(S鎖)[當事務(wù)A繼續(xù)修改數(shù)據(jù)M的時候,先釋放掉S鎖,再修改數(shù)據(jù),再加上S鎖],根據(jù)S鎖的特性,事務(wù)B可以讀到事務(wù)A修改后的數(shù)據(jù)(無論事務(wù)A是否提交,因為是共享鎖,隨時隨地都能查到數(shù)據(jù)A修改后的結(jié)果),事務(wù)B不能去修改數(shù)據(jù)M,直到事務(wù)A提交,釋放掉S鎖。

缺點:
可能會造成如下后果

丟失更新。

臟讀。

不可重復讀。

幻讀。

例子:MySql 5.5 證明一級封鎖協(xié)議會造成臟讀,不可重復讀。

A客戶端修改數(shù)據(jù)M,B客戶端設(shè)置不同的隔離級別去查看數(shù)據(jù)M,論證該級別下會發(fā)生臟讀,不可重復讀(相當于客戶端A修改的數(shù)據(jù)已經(jīng)寫到表里,客戶端B傳不同版本號[隔離級別],去查看數(shù)據(jù)M,所得的查詢結(jié)果也不同)。

客戶端A設(shè)置手動提交,并且開啟事務(wù)A。

客戶端B設(shè)置手動提交,修改事務(wù)隔離級別為read-uncommitted,并且開啟事務(wù)B(一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交)

事務(wù)B查詢數(shù)據(jù)M。

事務(wù)A修改其中一行數(shù)據(jù)(查詢原有基礎(chǔ)數(shù)據(jù),然后把id = 1 的name 修改為4 )。

事務(wù)B查看數(shù)據(jù)M,發(fā)現(xiàn)事務(wù)B讀到了事務(wù)A未提交的數(shù)據(jù),發(fā)生了臟讀。

事務(wù)A回滾。

客戶端B查詢的情況。

在同一個事務(wù)B里,查詢同一個數(shù)據(jù)M,居然2次不一樣,造成不可重復讀,其中有一次數(shù)據(jù)是無效的數(shù)據(jù),臟讀了。
假如事務(wù)A不回滾呢? 那么事務(wù)B就沒造成臟讀,不可重復讀。

例子:MySql 5.5 證明一級封鎖協(xié)議會造成更新丟失

事務(wù)A提交數(shù)據(jù)M。

事務(wù)B查詢數(shù)據(jù)M,事務(wù)B查詢的數(shù)據(jù)M,沒有臟數(shù)據(jù),并且2次結(jié)果一致,沒出現(xiàn)不可重復讀。

事務(wù)B修改數(shù)據(jù)M。

此時事務(wù)A對數(shù)據(jù)M的修改被事務(wù)B給覆蓋,造成了更新丟失。

例子:MySql 5.5 證明一級封鎖協(xié)議會造成幻讀

客戶端A設(shè)置手動提交,并且開啟事務(wù)A。

客戶端B設(shè)置手動提交,修改事務(wù)隔離級別為read-uncommitted,并且開啟事務(wù)B(一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交)

事務(wù)B查詢數(shù)據(jù)M。

事務(wù)A插入一條數(shù)據(jù)。

事務(wù)B查詢數(shù)據(jù)M。

事務(wù)B第二次查詢的時候,數(shù)據(jù)M多了一行,像是發(fā)生了幻覺似的,有可能這一行是無效數(shù)據(jù)(當事務(wù)A回滾)。

二級封鎖協(xié)議

二級封鎖協(xié)議對應(yīng)READ-COMMITTED隔離級別,本質(zhì)是事務(wù)A在修改數(shù)據(jù)M后立刻加X鎖,事務(wù)B不能修改數(shù)據(jù)M,同時不能查詢到最新的數(shù)據(jù)M(避免臟讀),查詢到的數(shù)據(jù)M是上一個版本(Innodb MVCC快照)的。

優(yōu)點:
1.避免臟讀。

缺點:
可能會造成如下后果

丟失更新。

不可重復讀。

幻讀。

例子:MySql 5.5 證明二級封鎖協(xié)議不會造成臟讀,但是會造成不可重復讀(幻讀,丟失更新,和上面證明方式一樣,這里暫不證明了)
A客戶端修改數(shù)據(jù)M,B客戶端設(shè)置不同的隔離級別去查看數(shù)據(jù)M,論證該級別下會發(fā)生不可重復讀(相當于客戶端A修改的數(shù)據(jù)已經(jīng)寫到表里,客戶端B傳不同版本號[隔離級別],去查看數(shù)據(jù)M,所得的查詢結(jié)果也不同)。

客戶端A設(shè)置手動提交,并且開啟事務(wù)A。

客戶端B設(shè)置手動提交,修改事務(wù)隔離級別為read-committed,并且開啟事務(wù)B(一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交)。

事務(wù)A修改其中一行數(shù)據(jù)(查詢原有基礎(chǔ)數(shù)據(jù),然后把id = 1 的name 修改為4 )。

事務(wù)B查詢數(shù)據(jù)M,數(shù)據(jù)還是和之前的一樣(沒有發(fā)生臟讀),事務(wù)B讀不到了事務(wù)A未提交的數(shù)據(jù)。

事務(wù)A提交。

事務(wù)B查詢數(shù)據(jù),數(shù)據(jù)M被修改。

在同一個事務(wù)B中,查詢數(shù)據(jù)M,2次結(jié)果不一致,證明發(fā)生了不可重復讀。

三級封鎖協(xié)議

三級封鎖協(xié)議對應(yīng)REPEATABLE-READ隔離級別,本質(zhì)是二級封鎖協(xié)議基礎(chǔ)上,對讀到的數(shù)據(jù)M瞬間加上共享鎖,直到事務(wù)結(jié)束才釋放(保證了其他事務(wù)沒辦法修改該數(shù)據(jù)),這個級別是MySql 5.5 默認的隔離級別。

優(yōu)點:
1.避免臟讀。
2.避免不可重復讀。

缺點:

幻讀。

丟失更新。

例子:MySql 5.5 證明三級封鎖協(xié)議不會造成臟讀,不可重復讀(造成幻讀,丟失更新,和上面證明方式一樣,但是要在非mysql數(shù)據(jù)庫上證明,后面有解釋,這里暫不證明了)

客戶端A設(shè)置手動提交,并且開啟事務(wù)A。

客戶端B設(shè)置手動提交,修改事務(wù)隔離級別為repeatable-read,并且開啟事務(wù)B(一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交)。

事務(wù)A查詢數(shù)據(jù)M。

事務(wù)B查詢數(shù)據(jù)M。

事務(wù)A更新數(shù)據(jù)M。

事務(wù)B查詢數(shù)據(jù)M,發(fā)現(xiàn)查詢的結(jié)果沒變化,避免了臟讀。

事務(wù)A提交事務(wù)。

事務(wù)B查詢數(shù)據(jù)M,還是和之前查詢的結(jié)果一樣,沒有變化,避免了不可重復讀。

事務(wù)B提交事務(wù)

這個時候事務(wù)B才能查詢到最新的數(shù)據(jù)M+。

例子:MySql 5.5 證明Mysql Innodb引擎的三級封鎖協(xié)議不會造成幻讀

mysql innodb的reapetable read級別是避免了幻讀,mysql的實現(xiàn)和標準定義的RR隔離級別有差別,詳情見 how-to-produce-phantom-reads。

客戶端A設(shè)置手動提交,并且開啟事務(wù)A。

客戶端B設(shè)置手動提交,修改事務(wù)隔離級別為repeatable-read,并且開啟事務(wù)B(一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交)。

事務(wù)A查詢數(shù)據(jù)M。

事務(wù)B查詢數(shù)據(jù)M。

事務(wù)A對記錄M插入一條數(shù)據(jù)。

事務(wù)A提交。

事務(wù)B查看數(shù)據(jù)M。

看不到事務(wù)A新增加的一條數(shù)據(jù),說明避免了幻讀。

事務(wù)B插入一條記錄。

明明剛剛查詢到?jīng)]有ID為4的,現(xiàn)在居然插不進去,哈哈哈哈哈。

例子:MySql 5.5 證明三級封鎖協(xié)議在讀到數(shù)據(jù)的瞬間加上共享鎖,等事務(wù)結(jié)束才釋放以及三級封鎖協(xié)議會造成更新丟失

客戶端A重新開啟事務(wù)A。

客戶端B設(shè)置手動提交,修改事務(wù)隔離級別為read-committed,并且開啟事務(wù)B(一定要在開啟事務(wù)前修改事務(wù)的隔離級別,不然當前還是保持著原來的事務(wù)隔離級別,直到當前事務(wù)提交)。

事務(wù)A修改數(shù)據(jù)M。

事務(wù)B也修改數(shù)據(jù)M,事務(wù)B的修改進程被掛起,因為事務(wù)A在對數(shù)據(jù)M修改后瞬間加上了共享鎖,對于其他事務(wù)只能讀。

事務(wù)A提交事務(wù)。

事務(wù)B的修改進程被喚起(等待4.98秒)。

事務(wù)B提交修改。

最終事務(wù)A,事務(wù)B查詢數(shù)據(jù)M。

事務(wù)B的修改把事務(wù)A的修改給覆蓋了,造成了更新丟失。

最強封鎖協(xié)議

最強封鎖協(xié)議對應(yīng)Serialization隔離級別,本質(zhì)是從MVCC并發(fā)控制退化到基于鎖的并發(fā)控制,對事務(wù)中所有讀取操作加S鎖,寫操作加X鎖,這樣可以避免臟讀,不可重復讀,幻讀,更新丟失,開銷也最大,會造成讀寫沖突,并發(fā)程度也最低。

例子:MySql 5.5 證明三級封鎖協(xié)議不會造成幻讀

客戶端A重新開啟事務(wù)A

客戶端B設(shè)置手動提交,修改隔離級別為SERIALIZABLE,并且開啟事務(wù)B。

事務(wù)A插入數(shù)據(jù),并且提交。

事務(wù)B查詢數(shù)據(jù),依然還是之前的數(shù)據(jù),避免的幻讀。

事務(wù)A修改數(shù)據(jù),被掛起。

證明了Serialization級別下寫操作是對數(shù)據(jù)M加的是X鎖。

總結(jié)

ANSI SQL 隔離級級別

隔離性 臟讀可能性 不可重復讀可能性 幻讀可能性 加鎖讀
READ-UNCOMMITTED Y Y Y N
READ-COMMITTED N Y Y N
REPEATABLE-READ N N Y N
SERIALIZABLE N N N Y

感謝您的耐心閱讀,如果您發(fā)現(xiàn)文章中有一些沒表述清楚的,或者是不對的地方,請給我留言,您的鼓勵是作者寫作最大的動力,
如果您認為本文質(zhì)量不錯,讀后覺得收獲很大,不妨請我喝杯咖啡,讓我更有動力繼續(xù)寫出高質(zhì)量的文章。

支付寶

微信

作 者 : @mousycoder

原文出處 : http://mousycoder.com/2016/02/19/explain-transaction-in-simple-language-3/

創(chuàng)作時間:2016-2-19

更新時間:2016-2-22

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65501.html

相關(guān)文章

  • 深入理解 MySQL ——鎖、事務(wù)與并發(fā)控制

    摘要:鎖共享鎖與排他鎖它們都是標準的行級鎖。防止任何其他事務(wù)變動的行。間隙鎖是性能和并發(fā)性之間權(quán)衡的一種折衷,用于某些特定的事務(wù)隔離級別,如級別級別,我司為了減少死鎖,關(guān)閉了鎖,使用級別。 本文首發(fā)于 vivo 互聯(lián)網(wǎng)技術(shù)微信公眾號 https://mp.weixin.qq.com/s/JF...作者:張碩 本文對 MySQL 數(shù)據(jù)庫中有關(guān)鎖、事務(wù)及并發(fā)控制的知識及其原理做了系統(tǒng)化的介紹和總...

    Dr_Noooo 評論0 收藏0
  • [靈魂拷問]MySQL面試高頻100問(工程師方向)

    摘要:黑客技術(shù)點擊右側(cè)關(guān)注,了解黑客的世界開發(fā)進階點擊右側(cè)關(guān)注,掌握進階之路開發(fā)點擊右側(cè)關(guān)注,探討技術(shù)話題作者丨呼延十排版丨團長前言本文主要受眾為開發(fā)人員所以不涉及到的服務(wù)部署等操作且內(nèi)容較多大家準備好耐心和瓜子礦泉水前一陣系統(tǒng)的學習了一下也有 ...

    gyl_coder 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<