<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
上一篇文章講解了MySQL的事務的相關概念MySQL的事務特性概念梳理總結
文章末尾提出了事務因並行出現的問題有哪些?
本篇將著重講述這個問題的前因後果及解決方式。
概念:一個事務讀取到其他事務未提交的資料。
用一個圖來講解,在並行環境下,多個事務操作同一物件帶來的問題:
概念:一個事務在一個時間段內 前後讀取的資料不一致,或者出現了修改/刪除。
概念:事務A 按照查詢條件讀取某個範圍的記錄,其他事務又在該範圍內出入了滿足條件的新記錄,當事務A再次讀取資料到時候我們發現多了滿足記錄的條數(幻行)
建議大家把幻讀記作幻行,以免和不可重複讀記混淆
前提:兩者都是讀取到已經提交的資料
不可重複讀:重點是在於修改,在一個事務中,同樣的條件,第一次讀取的資料與第二次【資料不一樣】(因為中間有其他事務對這個資料進行了修改)
幻讀:重點在於新增或者刪除,在一個事務中,同樣的條件(範圍),第一次讀取和第二讀取【記錄條數不一樣】(因為中間有其他事務在這個範圍裡插入、刪除了的資料)
我們現在已經知道,原來事務並行會出現,髒讀,不可重複讀,幻讀的問題。
那這些問題我們都是需要去解決的,怎麼解決呢?
有興趣可以看看官網是怎麼解釋的
連結: 官網地址
事務並行的三大問題其實都是資料庫讀一致性問題,必須由資料庫提供一定的事務隔離機制來解決。
我們通過事務的隔離級別來解決不同的問題,那麼,不同的隔離級別解決了什麼問題呢?
其實sql標準92版 官方都有定義出來
另外,sql標準不是資料庫廠商定義出來的,大家不要以為sql語言是什麼mysql,sqlserver搞出來的,我們會發現每個資料庫語句的sql語句都是差不多的。sql是獨立於廠商的!!SQL是Structured Query Language的縮寫,本來就屬於一種查詢語言!!
官網支援四種隔離級別:
# 修改當前對談的隔離級別 # 讀未提交 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; # 讀已提交 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; # 可重複讀 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; # 序列化 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
我們也可以通過SQL去查詢當前的隔離級別
SHOW GLOBAL VARIABLES LIKE '%isolation%'; //全域性隔離級別 SHOW SESSION VARIABLES LIKE '%isolation%'; set SESSION autocommit=0; //關閉自動提交
事務隔離級別越高,多個事務在並行存取資料庫時互相產生資料干擾的可能性越低,但是並行存取的效能就越差。(相當於犧牲了一定的效能去保證資料的安全性)
多個事務同時修改一條記錄,A事務對其的改動在A事務還沒提交時,在B事務中就可以看到A事務對其的改動。
結論:沒有解決任何問題,存在髒讀,因為他就是讀取最新的資料。
多個事務同時修改一條記錄,A事務對其的改動在A事務提交之後,在B事務中可以看到A事務對其的改動。
結論:我就讀取你已經提交的事務就完事,解決髒讀。
多個事務同時修改一條記錄,這條記錄在A事務執行期間是不變的(別的事務對這條記錄的修改不被A事務感知)。
結論:RR級別解決了髒讀、不可重複讀、幻讀的問題。
多個事務同時存取一條記錄(CRUD),讀加讀鎖,寫加寫鎖,完全退化成了序列的存取,自然不會收到任何其他事務的干擾,效能最低。
結論:加鎖排隊讀取,效能最低。
可以看出,RU與序列化都沒啥實用意義,主要還是看RC和RR,那麼Mysql是怎麼實現這兩種隔離級別的呢?
我們要先學習Mysql的兩種機制,undo
版本鏈機制以及read view
快照讀機制,讀已提交和可重複讀隔離級別的實現都是建立在這兩個核心機制之上。
undo 版本鏈就是指undo log的儲存在邏輯上的表現形式,它被用於事務當中的回滾操作以及實現MVCC
,這裡介紹一下undo log之所以能實現回滾記錄的原理。
對於每一行記錄,會有兩個隱藏欄位:row_trx_id
和roll_pointer
row_trx_id
表示更新(改動)本條記錄的全域性事務id (每個事務建立都會分配id,全域性遞增,因此事務id區別對某條記錄的修改是由哪個事務作出的)roll_pointer
是回滾指標,指向當前記錄的前一個undo log版本,如果是第一個版本則roll_pointer
指向null,這樣如果有多個事務對同一條記錄進行了多次改動,則會在undo log中以鏈的形式儲存改動過程。
在上圖中,最下方的undo log中記錄了當前行的最新版本,而該條記錄之前的版本則以版本鏈的形式可追溯,這也是事務回滾所做的事。那undo log版本鏈和事務的隔離性有什麼關係呢?那就要引入另一個核心機制:read view。
read view表示讀檢視,這個快照讀會記錄四個關鍵的屬性:
當一個事務讀取某條記錄時會追溯undo log版本鏈,找到第一個可以存取的版本,而該記錄的某一個版本是否能被這個事務讀取到遵循如下規則:
(這個規則永遠成立,這個需要好好理解,對後面講解可重複讀和讀已提交兩個級別的實現密切相關)
RR中 Read View是事務第一次查詢的時候建立的。RC的Read View是事務每次查詢的時候建立的。
Oracle、Postgres等等其他資料庫都有MVCC的實現。
需要注意,在InnoDB中,MVCC和鎖是協同使用的,這兩種方案並不是互斥的。
配合使用read view和undo log版本鏈就能實現事務之間並行存取相同記錄時,可以根據事務id不同,獲取同一行的不同undo log版本(多版本並行控制)。
多版本並行控制,是什麼意思呢?版本控制,我們在進行查詢的時候是有版本的,後續在同一個事務裡查詢的時候,我們都是使用我們當初建立的快照版本。
比如說嘛,快照,你10歲20歲30歲40歲去照相,你只能看到你之前照相的模樣,但是不能看到你未來的模樣。
MVCC怎麼去實現?
每個事務都有一個事務ID,並且是遞增,我們後續MVCC的原理都是基於它去完成。
效果:建立一個快照,同一個事務無論查詢多少次都是相同的資料。
一個事務能看見的版本:
一個事務不能看見的版本:
下面通過模擬並行存取的兩個事務操作,介紹MVCC的實現(具體來說就是可重複讀和讀已提交兩個隔離級別的實現)
下面模擬兩個並行存取同一條記錄的事務AB的行為,假設這條記錄初始時id=1,a=0,該記錄兩個隱藏欄位row_trx_id = 100,roll_pointer = null
注意:在可重複讀隔離級別下,當事務sql執行的時候,會生成一個read view快照,且在本事務週期內一直使用這個read view,下面給出了並行存取同一條記錄的兩個事務AB的具體執行過程,並解釋可重複讀是如何實現的(解決了髒讀和不可重複讀)。
事務A的read view:
create_trx_id = 101| m_idx = [101, 102]|min_trx_id = 101|max_trx_id = 103
事務B的read view:
create_trx_id = 102| m_idx = [101, 102]|min_trx_id = 101|max_trx_id = 103
(ps. 這裡因為AB事務是並行執行,因此兩個事務建立的read view的max_trx_id = 103)
這裡要注意的是,每次對一條記錄發生修改,就會記錄一個undo log的版本,則在A事務中第二次查詢id=1的記錄的a的值的時候,B事務對該記錄的修改已經新增到版本鏈上了,此時這個undo log的trx_id = 102,在A事務的read view的m_idx陣列中且不等於A事務的trx_id = 101,因此無法存取到,需要在向前回溯,這裡找到trx_id = 100的記錄版本(小於A事務read view的min_trx_id屬性,因此可以存取到),故A事務第二次查詢依舊得到a = 0,而不是B事務修改的a = 1。
你可能有疑問,在A事務第二次查詢的時候,B事務已經完成提交了,那麼A事務的read view的m_idx陣列應該移除102才對啊,它存的不是當前活躍的事務的id嗎?·
注意:在可重複讀隔離級別下,當事務sql執行的時候,會生成一個read view快照,且在本事務週期內一直使用這個read view,雖然102確實應該從A事務的read view中移除,但是因為read view在可重複讀隔離級別下只會在第一條SQL執行時建立一次,並始終保持不變直到事務結束。
那麼也就明白了,在可重複讀隔離級別下,因為read view只在第一條SQL執行時建立,因此並行存取的其他事務提交前改動的髒資料、以及並行存取的其他事務提交的改動資料都對當前事務是透明的(儘管確實是記錄在了undo log版本鏈中) ,這就解決了髒讀和不可重複讀(即使其他事務提交的修改,對A事務來說前後查詢結果相同)的問題!
還是藉助上面事務處理的例子,所有的事務處理流程不變,只是將隔離級別調整為讀已提交,讀已提交依舊遵守read view和undo log版本鏈機制,它和可重複讀級別的區別在於,每次執行sql,都會建立一個read view,獲取最新的事務快照。 而因為這個區別,讀已提交產生了不可重複讀的問題,下面來分析一下原因:
事務A第一次查詢建立的read view:
create_trx_id = 101| m_idx = [101, 102]|min_trx_id = 101|max_trx_id = 103
事務B的read view:
create_trx_id = 102| m_idx = [101, 102]|min_trx_id = 101|max_trx_id = 103
事務A第二次查詢建立的read view:
create_trx_id = 101| m_idx = [101]|min_trx_id = 101|max_trx_id = 103
(ps. 這裡因為AB事務是並行執行,因此兩個事務建立的read view的max_trx_id = 103)
這裡重點觀察A事務的第二次查詢,之前你可能就意識到了,在事務B完成提交後,當前系統中活躍的事務id應該移除102,但是因為在可重複讀隔離級別下,A事務的read view只會在第一個SQL執行時建立,而在讀已提交隔離級別下,每次執行SQL都會建立最新的read view,且此時 m_idx陣列中移除了102,那麼事務A在追溯undo log版本鏈的時候,最新版本記錄的trx_id = 102,102不在A事務的m_idx陣列中,且101 = min_trx_id <= 102 < max_trx_id = 103,因此可以存取到B事務的提交結果。
那麼對A事務來說,在事務過程中讀取同一條記錄第一次得到a=0,第二次得到a=1,所以出現了不可重複讀的問題(這裡B不提交的話A如果就進行了第二次查詢,則102不會從A事務的read view移除,則A事務依舊存取不到B事務未提交的修改,因此髒讀還是可以避免的!)
MVCC多版本並行控制的實現可以理解成讀已提交、可重複讀兩種隔離級別的實現,通過控制read view的建立時機(其存取機制是不變的),配合undo log版本鏈可以實現事務之間對同一條記錄的並行存取,並獲得不同的結果。
但是,大家有沒有想過,剛才的一切都是對A提供便利,對B呢?
而且,MVCC 是適合用於處查詢的時候使用,能提供很高的效能,我們的事務不僅僅
是隻有讀,我們還有寫情況,剛才介紹的情況,B的事務是不是會被直接覆蓋掉?這不就造成了事務丟失了嘛
針對寫的情況,Mysql還有另一種基於鎖的機制
鎖的作用是什麼?它跟Java裡面的鎖是一樣的,是為了解決資源競爭的問題,Java裡面的資源是物件,資料庫的資源就是資料表或者資料行。
基於鎖的方式起始比較簡單,就是一個事務在進行資料查詢時,不允許其他事務修改。也就是說,基於鎖的機制就使得資料庫無法支援並行事務的讀寫操作,這種方案在一定程度上影響了運算元據的效率。
本文著重講InnoDB引擎
在之前講MySQL儲存引擎的時候,我們知道了 InnoDB和MylSAM支援的鎖 的型別是不同的。InnoDB同時支援表鎖和行鎖,而MylSAM只支援表鎖,用lock table的語法加鎖。
lock tables xxx read; lock tables xxx write; unlock tables ;
為什麼支援行鎖會成為InnoDB的優勢?表鎖和行鎖的區別到底在哪?
我們可以看到,官網把鎖分成了8類。我們把前面的兩個行級別的鎖(Shared andExclusive Locks),和兩個表級別的鎖(Intention Locks)稱為鎖的基本模式。
show variables like 'innodb_autoinc_lock_mode'; --0: traditonal(每次都會產生表鎖) --1: consecutive(會產生一個輕量鎖,simple insert 會獲得批次的鎖,保證連續插入,預設值) --2: interleaved(不會鎖表,來一個處理一個,並行最高)
空間索引的謂詞鎖:Predicate Locks for Spatial Indexes是5.7版本里面新增的空間索引的謂詞鎖。
第一個行級別的鎖就是我們在官網看到的Shared Locks(共用鎖),我們獲取了一行資料的讀鎖以後,可以用來讀取資料,所以它也叫做讀鎖,注意不要在加上了讀鎖以後去寫資料,不然的話可能會出現死鎖的情況。而且多個事務可以共用一把讀鎖。
共用鎖的作用:因為共用鎖會阻塞其他事務的修改,所以可以用在不允許其他事務修改資料的情況。
那怎麼給一行資料加上讀鎖呢?
我們可以用select… lock in share mode;的方式手工加上一把讀鎖。
釋放鎖有兩種方式,只要事務結束,鎖就會自動事務,包括提交事務和結束事務。
第二個行級別的鎖叫做Exclusive Locks(排它鎖),它是用來運算元據的,所以又叫做寫鎖。只要一個事務獲取了一行資料的排它鎖,其他的事務就不能再獲取這一行資料的共用鎖和排它鎖。
排它鎖的加鎖方式有兩種
第一種是自動加排他鎖,可能是同學們沒有注意到的:我們在運算元據的時候,包括增刪改,都會預設加上一個排它鎖。
第二種是手工加鎖,我們用一個FOR UPDATE給一行資料加上一個排它鎖,這個無論是在我們的程式碼裡面還是運算元據的工具裡面,都比較常用。
釋放鎖的方式跟前面是一樣的。
這個是兩個行鎖,接下來就是兩個表鎖。
意向鎖是什麼呢?我們好像從來沒有聽過,也從來沒有使用過,其實他們是由資料庫自己維護的。
也就是說:
反過來:
意向鎖跟意向鎖是不衝突的,意向鎖跟行鎖也不衝突。
那麼這兩個表級別的鎖存在的意義是什麼呢?
如果說沒有意向鎖的話,當我們準備給一張表加上表鎖的時候,我們首先要做什麼?是不是必須先要去判斷有沒其他的事務鎖定了其中了某些行?如果有的話,肯定不能加上表鎖。那麼這個時候我們就要去掃描整張表才能確定能不能成功加上一個表鎖,如果資料量特別大,比如有上千萬的資料的時候,加表鎖的效率是不是很低?
但是我們引入了意向鎖之後就不一樣了。我只要判斷這張表上面有沒有意向鎖,如果有,就直接返回失敗。如果沒有,就可以加鎖成功。所以InnoDB裡面的表鎖,我們可以把它理解成一個標誌。就像火車上衛生間有沒有人使用的燈,讓你不用去推門,是用來提高加鎖的效率的。
所以鎖是用來解決事務對資料的並行存取的問題的。那麼,鎖到底鎖住了什麼呢?
當一個事務鎖住了一行資料的時候,其他的事務不能操作這一行資料,那它到底是鎖住了這一行資料,還是鎖住了這一個欄位,還是鎖住了別的什麼東西呢?
首先我們有三張表,一張沒有索引的t1,一張有主鍵索引的t2,一張有唯一索引的t3。
我們先假設 InnoDB的行鎖 鎖住的是一行資料或者一條記錄。
我們假設t1的表結構,它有兩個欄位, int型別的id和varchar型別的name。裡面有4條資料,1、2、3、4。
我們在兩個對談裡面手工開啟兩個事務。
在第一個事務裡面,我們通過 where id =1鎖住第一行資料。
在第二個事務裡面,我們嘗試給id=3的這一行資料加鎖,能成功嗎?
很遺憾,我們看到紅燈亮起,這個加鎖的操作被阻塞了。這就有點奇怪了,第一個事務鎖住了id=1的這行資料,為什麼我不能操作id=3的資料呢?
我們再來操作一條不存在的資料,插入 id=5。它也被阻塞了。實際上這裡整張表都被鎖住了。所以,我們的第一個猜想被推翻了,InnoDB的行鎖鎖住的應該不是Record。
那為什麼在沒有索引或者沒有用到索引的情況下,會鎖住整張表?這個問題我們先留在這裡。
我們假設t2的表結構。欄位和t1是一樣的,不同的地方是id上建立了一個主鍵索引。裡面的資料是1、4、7、10。
第一種情況,使用相同的id值去加鎖,衝突;使用不同的id 加鎖,可以加鎖成功。那麼,既然不是鎖定一行資料,有沒有可能是鎖住了id 的這個欄位
呢?
我們假設t3的表結構欄位還是一樣的, id上建立了一個主鍵索引,name 上建立了一個唯一索引。裡面的資料是1、4、7、10。
在第一個事務裡面,我們通過name欄位去鎖定值是4的這行資料。
在第二個事務裡面,嘗試獲取一樣的排它鎖,肯定是失敗的,這個不用懷疑。
在這裡我們懷疑InnoDB的行鎖鎖住的是欄位,所以這次我換一個欄位,用id=4去給這行資料加鎖,能成功嗎?
很遺憾,又被阻塞了,說明行鎖鎖住的是欄位的這個推測也是錯的,否則就不會出現第一個事務鎖住了name,第二個欄位鎖住id失敗的情況。
既然鎖住的不是record,也不是column,,行列都沒鎖,那InnoDB的行鎖鎖住的到底是什麼呢?在這三個案例裡面,我們要去分析一下他們的差異在哪裡,也就是這三張表的結構,是什麼區別導致了加鎖的行為的差異?其實答案就是索引。InnoDB的行鎖,就是通過鎖住索引來實現的。
那麼我們還有兩個問題沒有解決:
1、為什麼表裡面沒有索引的時候,鎖住一行資料會導致鎖表?或者說,如果鎖住的是索引,一張表沒有索引怎麼辦?
所以,一張表有沒有可能沒有索引?
ROWID
(每一行都有的內建,或者說隱藏的列
)作 為隱藏的聚集索引,它會隨著行記錄的寫入而主鍵遞增。所以,為什麼鎖表,是因為查詢沒有使用索引,會進行全表掃描,然後把每一個隱藏的聚集索引都鎖住了。
2、為什麼通過唯一索引給資料行加鎖,主鍵索引也會被鎖住?
大家還記得在InnoDB裡面,當我們使用輔助索引(二級索引)的時候,它是怎麼檢索資料的嗎?輔助索引的葉子節點儲存的是什麼內容?
在輔助索引裡面,索引儲存的是二級索引和主鍵的值。比如name=4,儲存的是name的索引和主鍵id 的值4。
而主鍵索引裡面除了索引之外,還儲存了完整的資料。所以我們通過輔助索引鎖定一行資料的時候,它跟我們檢索資料的步驟是一樣的,會通過主鍵值找到主鍵索引,然後也鎖定。
本質上是因為鎖定的是同一行資料,是相互衝突的。
問題1-幻讀問題(InnoDB)
範圍查詢的時候,多次查詢結果的資料行數一致
select * from table where id >=1 and id<=4 //鎖定2,3 [解決幻讀問題]
問題二, for update 實現了排他鎖(行鎖)
--transaction1 select * from table where id=1 for update; //查詢主鍵id=1 (行 鎖,只鎖定行) --transaction2 update table set name='111' where id=1; //阻塞 update table set name='222' where name =''; //阻塞
基於索引來決定的,如果where是索引,那麼這個時候,直接加行鎖.
問題三, 鎖定整個表
select * from table for update; //表鎖 update table set name='111' where id=1; //阻塞
我們先來看一下我們測試用的表,t2,這張表有一個主鍵索引,前面我們已經見過了。我們插入了4行資料,主鍵id分別是1、4、7、10。
為了讓大家真正理解這三種行鎖演演算法的區別,我也來花一點時間給大家普及一下這三種範圍的概念。
因為我們用主鍵索引加鎖,我們這裡的劃分標準就是主鍵索引的值。
這些資料庫裡面存在的主鍵值,我們把它叫做Record(記錄),那麼這裡我們就有4個Record。
根據主鍵,這些存在的Record隔開的資料不存在的區間,我們把它叫做Gap(間隙),它是一個左開右開
的區間。
假設我們有N個Record,那麼所有的資料會被劃分成多少個Gap 區間?答案是N+1,就像我們把一條繩子砍N刀,它最後肯定是變成N+1段。
最後一個,間隙(Gap)連同它左邊的記錄(Record),我們把它叫做臨鍵的區間
,它是一個左開右閉的區間。再重複一次,是左開右閉。
整型的主鍵索引,它是可以排序,所以才有這種區間。如果我的主鍵索引不是整形,是字元怎麼辦呢?
任何一個字元集,都有相應的排序規則:
第一種情況,當我們對於唯一性的索引(包括唯一索引和主鍵索引)使用等值查詢,精準匹配到一條記錄的時候,這個時候使用的就是記錄鎖。
顧名思義,記錄鎖就是為某行記錄加鎖,它封鎖該行的索引記錄,並不是真正的資料記錄,鎖的是索引的鍵值對。
-- 記錄鎖:id 列為主鍵列或唯一索引列 SELECT * FROM user WHERE id = 1 FOR UPDATE; --意味著id=1的這條記錄會被鎖住
第二種情況,當我們查詢的記錄不存在,沒有命中任何一個record,無論是用等值查詢還是範圍查詢的時候,它使用的都是間隙鎖。
還有個情況,假如我們只命中間隙的一邊,另一邊無法命中怎麼辦?
這種情況下,會鎖住另一邊的無限空間
顧名思義 鎖間隙,不鎖記錄。
重複一遍,當查詢的記錄不存在的時候,使用間隙鎖。
注意,間隙鎖主要是阻塞插入insert。相同的間隙鎖之間不衝突。
間隙鎖是基於非唯一索引,它鎖定一段範圍內的索引記錄,比如下面這個查詢
SELECT * FROM user WHERE id BETWEN 1 AND 4 FOR UPDATE;
那麼意味著所有在(1,4)區間內的記錄行都會被鎖住,它是一個左右開區間的範圍,意味著在這種情況下, 會鎖住id為2,3的索引,但是1、4不會被鎖定
第三種情況,當我們使用了範圍查詢,不僅僅命中了Record記錄,還包含了Gap間隙,在這種情況下我們使用的就是臨鍵鎖,它是MySQL裡面預設的行鎖演演算法,相當於記錄鎖加上間隙鎖。
唯一性索引,等值查詢匹配到一條記錄的時候,退化成記錄鎖。
沒有匹配到任何記錄的時候,退化成間隙鎖。
next Key Lock 可以理解為一種特殊的間隙鎖,也可以理解為一種特殊的演演算法,每個資料行上的非唯一索引列上都會存在一把臨鍵鎖,當某個事務持有該資料行的臨鍵鎖時,會鎖住一段左開右閉區間的資料。
為什麼要鎖住下一個左開右閉的區間?——就是為了解決幻讀的問題。
所以,我們再回過頭來看下這張圖片,為什麼InnoDB的RR級別能夠解決幻讀的問題,就是用臨鍵鎖實現的。
我們再回過頭來看下這張圖片,這個就是MySQL InnoDB裡面事務隔離級別的實現。
最後我們來總結一下四個事務隔離級別:
Read Uncommited
RU隔離級別:不加鎖。Serializable
Serializable 所有的select語句都會被隱式的轉化為select … in share mode,會和update、delete互斥。
這兩個很好理解,一般也不用,主要是RR和RC的區別?
Repeatable Read:RR隔離級別下,普通的select使用快照讀(snapshot read),底層使用MVCC來實
現。
加鎖的select(select … in share mode / select … for update)以及更新操作update, delete等語句使用當前讀(current read),底層使用記錄鎖、或者間隙鎖、臨鍵鎖
。
Read Commited:RC隔離級別下,普通的select 都是快照讀,使用MVCC 實現。加鎖的select都使用記錄鎖,因為沒有Gap Lock。
除了兩種特殊情況——外來鍵約束檢查(foreign-key constraint checking)以及重複鍵檢查(duplicate-key checking)時會使用間隙鎖封鎖區間。
所以RC會出現幻讀的問題。
RU和Serializable肯定不能用
RC和RR主要有幾個區別:
在RC中,一個update語句,如果讀到一行已經加鎖的記錄,此時 InnoDB返回記錄最近提交的版本,由MySQL上層判斷此版本是否滿足update的where 條件。若滿足(需要更新),則MySQL會重新發起一次讀操作,此時會讀取行的最新版本(並加鎖)。
實際上,如果能夠正確地使用鎖(避免不使用索引去枷鎖),只鎖定需要的資料,用預設的RR級別就可以了
在我們使用鎖的時候,有一個問題是需要注意和避免的,我們知道,排它鎖有互斥的特性。一個事務或者說一個執行緒持有鎖的時候,會阻止其他的執行緒獲取鎖,這個時候會造成阻塞等待,如果迴圈等待,會有可能造成死鎖。
死鎖的相關資訊,可以看我的下一篇部落格,MySQL死鎖的解析
連結: MySQL死鎖使用詳解及檢測和避免方法
到此這篇關於MySQL髒讀幻讀不可重複讀及事務的隔離級別和MVCC、LBCC實現的文章就介紹到這了,更多相關MySQL髒讀幻讀 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45