MySQL全局鎖、表鎖和行鎖的概念

這篇文章主要介紹“MySQL全局鎖、表鎖和行鎖的概念”,在日常操作中,相信很多人在MySQL全局鎖、表鎖和行鎖的概念問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”MySQL全局鎖、表鎖和行鎖的概念”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

含山ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

全局鎖

顧名思義,全局鎖就是對整個數(shù)據(jù)庫實(shí)例加鎖。MySQL提供了一個加全局讀鎖的方法,命令是Flush tables with read lock (FTWRL)。當(dāng)你需要讓整個庫處于只讀狀態(tài)的時候,可以使用這個命令,之后其他線程的以下語句會被阻塞:數(shù)據(jù)更新語句(數(shù)據(jù)的增刪改)、數(shù)據(jù)定義語句(包括建表、修改表結(jié)構(gòu)等)和更新類事務(wù)的提交語句。

全局鎖的典型使用場景是,做全庫邏輯備份。也就是把整庫每個表都select出來存成文本。

以前有一種做法,是通過FTWRL確保不會有其他線程對數(shù)據(jù)庫做更新,然后對整個庫做備份。注意,在備份過程中整個庫完全處于只讀狀態(tài)。但是讓整庫都只讀,聽上去就很危險:

  • 如果你在主庫上備份,那么在備份期間都不能執(zhí)行更新,業(yè)務(wù)基本上就得停擺。

  • 如果你在從庫上備份,那么備份期間從庫不能執(zhí)行主庫同步過來的binlog,會導(dǎo)致主從延遲

看來加全局鎖不太好。但是細(xì)想一下,備份為什么要加鎖呢?我們來看一下不加鎖會有什么問題。

假設(shè)你現(xiàn)在要維護(hù)CSDN的購買系統(tǒng),關(guān)注的是用戶賬戶余額表和用戶課程表。現(xiàn)在發(fā)起一個邏輯備份。假設(shè)備份期間,有一個用戶,他購買了一門課程,業(yè)務(wù)邏輯里就要扣掉他的余額,然后往已購課程里面加上一門課。

如果時間順序上是先備份賬戶余額表(u_account),然后用戶購買,然后備份用戶課程表(u_course),會怎么樣呢?你可以看一下這個圖:

MySQL全局鎖、表鎖和行鎖的概念
可以看到,這個備份結(jié)果里,用戶A的數(shù)據(jù)狀態(tài)是賬戶余額沒扣,但是用戶課程表里面已經(jīng)多了一門課。如果后面用這個備份來恢復(fù)數(shù)據(jù)的話,用戶A就發(fā)現(xiàn),自己賺了。

作為用戶可別覺得這樣可真好啊,你可以試想一下:如果備份表的順序反過來,先備份用戶課程表再備份賬戶余額表,又可能會出現(xiàn)什么結(jié)果?

也就是說,不加鎖的話,備份系統(tǒng)備份的得到的庫不是一個邏輯時間點(diǎn),這個視圖是邏輯不一致的。

說到視圖你肯定想起來了,我們在前面講事務(wù)隔離的時候,其實(shí)是有一個方法能夠拿到一致性視圖的,對吧?就是在可重復(fù)讀隔離級別下開啟一個事務(wù)。

官方自帶的邏輯備份工具是mysqldump。當(dāng)mysqldump使用參數(shù)–single-transaction的時候,導(dǎo)數(shù)據(jù)之前就會啟動一個事務(wù),來確保拿到一致性視圖。而由于MVCC的支持,這個過程中數(shù)據(jù)是可以正常更新的。

你一定在疑惑,有了這個功能,為什么還需要FTWRL呢?一致性讀是好,但前提是引擎要支持這個隔離級別。比如,對于MyISAM這種不支持事務(wù)的引擎,如果備份過程中有更新,總是只能取到最新的數(shù)據(jù),那么就破壞了備份的一致性。這時,我們就需要使用FTWRL命令了。

所以,single-transaction方法只適用于所有的表使用事務(wù)引擎的庫。如果有的表使用了不支持事務(wù)的引擎,那么備份就只能通過FTWRL方法。這往往是DBA要求業(yè)務(wù)開發(fā)人員使用InnoDB替代MyISAM的原因之一。

你也許會問,既然要全庫只讀,為什么不使用set global readonly=true的方式呢?確實(shí)readonly方式也可以讓全庫進(jìn)入只讀狀態(tài),但我還是會建議你用FTWRL方式,主要有兩個原因:

  • 一是,在有些系統(tǒng)中,readonly的值會被用來做其他邏輯,比如用來判斷一個庫是主庫還是備庫。因此,修改global變量的方式影響面更大,我不建議你使用。

  • 二是,在異常處理機(jī)制上有差異。如果執(zhí)行FTWRL命令之后由于客戶端發(fā)生異常斷開,那么MySQL會自動釋放這個全局鎖,整個庫回到可以正常更新的狀態(tài)。而將整個庫設(shè)置為readonly之后,如果客戶端發(fā)生異常,則數(shù)據(jù)庫就會一直保持readonly狀態(tài),這樣會導(dǎo)致整個庫長時間處于不可寫狀態(tài),風(fēng)險較高。

業(yè)務(wù)的更新不只是增刪改數(shù)據(jù)(DML),還有可能是加字段等修改表結(jié)構(gòu)的操作(DDL)。不論是哪種方法,一個庫被全局鎖上以后,你要對里面任何一個表做加字段操作,都是會被鎖住的。

但是,即使沒有被全局鎖住,加字段也不是就能一帆風(fēng)順的,因?yàn)槟氵€會碰到接下來我們要介紹的表級鎖。

表級鎖

MySQL里面表級別的鎖有兩種:一種是表鎖,一種是元數(shù)據(jù)鎖(meta data lock,MDL)。

表鎖的語法是 lock tables … read/write。與FTWRL類似,可以用unlock tables主動釋放鎖,也可以在客戶端斷開的時候自動釋放。需要注意,lock tables語法除了會限制別的線程的讀寫外,也限定了本線程接下來的操作對象。

舉個例子, 如果在某個線程A中執(zhí)行l(wèi)ock tables t1 read, t2 write; 這個語句,則其他線程寫t1、讀寫t2的語句都會被阻塞。同時,線程A在執(zhí)行unlock tables之前,也只能執(zhí)行讀t1、讀寫t2的操作。連寫t1都不允許,自然也不能訪問其他表。

在還沒有出現(xiàn)更細(xì)粒度的鎖的時候,表鎖是最常用的處理并發(fā)的方式。而對于InnoDB這種支持行鎖的引擎,一般不使用lock tables命令來控制并發(fā),畢竟鎖住整個表的影響面還是太大。

另一類表級的鎖是MDL(metadata lock)。MDL不需要顯式使用,在訪問一個表的時候會被自動加上。MDL的作用是,保證讀寫的正確性。你可以想象一下,如果一個查詢正在遍歷一個表中的數(shù)據(jù),而執(zhí)行期間另一個線程對這個表結(jié)構(gòu)做變更,刪了一,那么查詢線程拿到的結(jié)果跟表結(jié)構(gòu)對不上,肯定是不行的。

因此,在MySQL 5.5版本中引入了MDL,當(dāng)對一個表做增刪改查操作的時候,加MDL讀鎖;當(dāng)要對表做結(jié)構(gòu)變更操作的時候,加MDL寫鎖。

  • 讀鎖之間不互斥,因此你可以有多個線程同時對一張表增刪改查。

  • 讀寫鎖之間跟寫鎖之間是互斥的,用來保證變更表結(jié)構(gòu)操作的安全性。因此,如果有兩個線程要同時給一個表加字段,其中一個要等另一個執(zhí)行完才能開始執(zhí)行。

雖然MDL鎖是系統(tǒng)默認(rèn)會加的,但卻是你不能忽略的一個機(jī)制。比如下面這個例子,我經(jīng)常看到有人掉到這個坑里:給一個小表加個字段,導(dǎo)致整個庫掛了。

你肯定知道,給一個表加字段,或者修改字段,或者加索引,需要掃描全表的數(shù)據(jù)。在對大表操作的時候,你肯定會特別小心,以免對線上服務(wù)造成影響。而實(shí)際上,即使是小表,操作不慎也會出問題。我們來看一下下面的操作序列,假設(shè)表t是一個小表。MySQL全局鎖、表鎖和行鎖的概念
我們可以看到session A先啟動,這時候會對表t加一個MDL讀鎖。由于session B需要的也是MDL讀鎖,因此可以正常執(zhí)行。之后session C會被blocked,是因?yàn)閟ession A的MDL讀鎖還沒有釋放,而session C需要MDL寫鎖,因此只能被阻塞。

如果只有session C自己被阻塞還沒什么關(guān)系,但是之后所有要在表t上新申請MDL讀鎖的請求也會被session C阻塞。前面我們說了,所有對表的增刪改查操作都需要先申請MDL讀鎖,就都被鎖住,等于這個表現(xiàn)在完全不可讀寫了

如果某個表上的查詢語句頻繁,而且客戶端有重試機(jī)制,也就是說超時后會再起一個新session再請求的話,這個庫的線程很快就會爆滿。現(xiàn)在應(yīng)該知道了,事務(wù)中的MDL鎖,在語句執(zhí)行開始時申請,但是語句結(jié)束后并不會馬上釋放,而會等到整個事務(wù)提交后再釋放。

如何安全地給小表加字段
首先我們要解決長事務(wù),事務(wù)不提交,就會一直占著MDL鎖。在MySQL的information_schema 庫的 innodb_trx 表中,你可以查到當(dāng)前執(zhí)行中的事務(wù)。如果你要做DDL變更的表剛好有長事務(wù)在執(zhí)行,要考慮先暫停DDL,或者kill掉這個長事務(wù)。

但考慮一下這個場景。如果你要變更的表是一個熱點(diǎn)表,雖然數(shù)據(jù)量不大,但是上面的請求很頻繁,而你不得不加個字段,你該怎么做呢?

這時候kill可能未必管用,因?yàn)樾碌恼埱篑R上就來了。比較理想的機(jī)制是,在alter table語句里面設(shè)定等待時間,如果在這個指定的等待時間里面能夠拿到MDL寫鎖最好,拿不到也不要阻塞后面的業(yè)務(wù)語句,先放棄。之后開發(fā)人員或者DBA再通過重試命令重復(fù)這個過程。

MariaDB 已經(jīng)合并了AliSQL的這個功能,所以這兩個開源分支目前都支持DDL NOWAIT/WAIT n這個語法。

ALTER TABLE tbl_name NOWAIT add column ...ALTER TABLE tbl_name WAIT N add column ...

行鎖

MySQL的行鎖是在引擎層由各個引擎自己實(shí)現(xiàn)的。但并不是所有的引擎都支持行鎖,比如MyISAM引擎就不支持行鎖。不支持行鎖意味著并發(fā)控制只能使用表鎖,對于這種引擎的表,同一張表上任何時刻只能有一個更新在執(zhí)行,這就會影響到業(yè)務(wù)并發(fā)度。InnoDB是支持行鎖的,這也是MyISAM被InnoDB替代的重要原因之一

我們今天就主要來聊聊InnoDB的行鎖,以及如何通過減少鎖沖突來提升業(yè)務(wù)并發(fā)度

顧名思義,行鎖就是針對數(shù)據(jù)表中行記錄的鎖。這很好理解,比如事務(wù)A更新了一行,而這時候事務(wù)B也要更新同一行,則必須等事務(wù)A的操作完成后才能進(jìn)行更新。

當(dāng)然,數(shù)據(jù)庫中還有一些沒那么一目了然的概念和設(shè)計(jì),這些概念如果理解和使用不當(dāng),容易導(dǎo)致程序出現(xiàn)非預(yù)期行為,比如兩階段鎖。

從兩階段鎖說起

我先給你舉個例子。在下面的操作序列中,事務(wù)B的update語句執(zhí)行時會是什么現(xiàn)象呢?假設(shè)字段id是表t的主鍵。
MySQL全局鎖、表鎖和行鎖的概念
這個問題的結(jié)論取決于事務(wù)A在執(zhí)行完兩條update語句后,持有哪些鎖,以及在什么時候釋放。你可以驗(yàn)證一下:實(shí)際上事務(wù)B的update語句會被阻塞,直到事務(wù)A執(zhí)行commit之后,事務(wù)B才能繼續(xù)執(zhí)行。

知道了這個答案,你一定知道了事務(wù)A持有的兩個記錄的行鎖,都是在commit的時候才釋放的。也就是說,在InnoDB事務(wù)中,行鎖是在需要的時候才加上的,但并不是不需要了就立刻釋放,而是要等到事務(wù)結(jié)束時才釋放。這個就是兩階段鎖協(xié)議。

知道了這個設(shè)定,對我們使用事務(wù)有什么幫助呢?那就是,如果你的事務(wù)中需要鎖多個行,要把最可能造成鎖沖突、最可能影響并發(fā)度的鎖盡量往后放。我給你舉個例子。

假設(shè)你負(fù)責(zé)實(shí)現(xiàn)一個電影票在線交易業(yè)務(wù),顧客A要在影院B購買電影票。我們簡化一點(diǎn),這個業(yè)務(wù)需要涉及到以下操作:

  1. 從顧客A賬戶余額中扣除電影票價;

  2. 給影院B的賬戶余額增加這張電影票價;

  3. 記錄一條交易日志。

也就是說,要完成這個交易,我們需要update兩條記錄,并insert一條記錄。當(dāng)然,為了保證交易的原子性,我們要把這三個操作放在一個事務(wù)中。那么,你會怎樣安排這三個語句在事務(wù)中的順序呢?

試想如果同時有另外一個顧客C要在影院B買票,那么這兩個事務(wù)沖突的部分就是語句2了。因?yàn)樗鼈円峦粋€影院賬戶的余額,需要修改同一行數(shù)據(jù)。

根據(jù)兩階段鎖協(xié)議,不論你怎樣安排語句順序,所有的操作需要的行鎖都是在事務(wù)提交的時候才釋放的。所以,如果你把語句2安排在最后,比如按照3、1、2這樣的順序,那么影院賬戶余額這一行的鎖時間就最少。這就最大程度地減少了事務(wù)之間的鎖等待,提升了并發(fā)度。

好了,現(xiàn)在由于你的正確設(shè)計(jì),影院余額這一行的行鎖在一個事務(wù)中不會停留很長時間。但是,這并沒有完全解決你的困擾。

如果這個影院做活動,可以低價預(yù)售一年內(nèi)所有的電影票,而且這個活動只做一天。于是在活動時間開始的時候,你的MySQL就掛了。你登上服務(wù)器一看,CPU消耗接近100%,但整個數(shù)據(jù)庫每秒就執(zhí)行不到100個事務(wù)。這是什么原因呢?

這里,我就要說到死鎖死鎖檢測了。

死鎖和死鎖檢測

當(dāng)并發(fā)系統(tǒng)中不同線程出現(xiàn)循環(huán)資源依賴,涉及的線程都在等待別的線程釋放資源時,就會導(dǎo)致這幾個線程都進(jìn)入無限等待的狀態(tài),稱為死鎖。這里我用數(shù)據(jù)庫中的行鎖舉個例子。

MySQL全局鎖、表鎖和行鎖的概念
這時候,事務(wù)A在等待事務(wù)B釋放id=2的行鎖,而事務(wù)B在等待事務(wù)A釋放id=1的行鎖。 事務(wù)A和事務(wù)B在互相等待對方的資源釋放,就是進(jìn)入了死鎖狀態(tài)。當(dāng)出現(xiàn)死鎖以后,有兩種策略:

  • 一種策略是直接進(jìn)入等待,直到超時。這個超時時間可以通過參數(shù)innodb_lock_wait_timeout來設(shè)置。

  • 另一種策略是發(fā)起死鎖檢測,發(fā)現(xiàn)死鎖后,主動回滾死鎖鏈條中的某一個事務(wù),讓其他事務(wù)得以繼續(xù)執(zhí)行。將參數(shù)innodb_deadlock_detect設(shè)置為on,表示開啟這個邏輯。

在InnoDB中,innodb_lock_wait_timeout的默認(rèn)值是50s,意味著如果采用第一個策略,當(dāng)出現(xiàn)死鎖以后,第一個被鎖住的線程要過50s才會超時退出,然后其他線程才有可能繼續(xù)執(zhí)行。對于在線服務(wù)來說,這個等待時間往往是無法接受的。

但是,我們又不可能直接把這個時間設(shè)置成一個很小的值,比如1s。這樣當(dāng)出現(xiàn)死鎖的時候,確實(shí)很快就可以解開,但如果不是死鎖,而是簡單的鎖等待呢?所以,超時時間設(shè)置太短的話,會出現(xiàn)很多誤傷。

所以,正常情況下我們還是要采用第二種策略,即:主動死鎖檢測,而且innodb_deadlock_detect的默認(rèn)值本身就是on。主動死鎖檢測在發(fā)生死鎖的時候,是能夠快速發(fā)現(xiàn)并進(jìn)行處理的,但是它也是有額外負(fù)擔(dān)的。

你可以想象一下這個過程:每當(dāng)一個事務(wù)被鎖的時候,就要看看它所依賴的線程有沒有被別人鎖住,如此循環(huán),最后判斷是否出現(xiàn)了循環(huán)等待,也就是死鎖。那如果是我們上面說到的所有事務(wù)都要更新同一行的場景呢?

每個新來的被堵住的線程,都要判斷會不會由于自己的加入導(dǎo)致了死鎖,這是一個時間復(fù)雜度是O(n)的操作。假設(shè)有1000個并發(fā)線程要同時更新同一行,那么死鎖檢測操作就是1000*1000 = 100萬這個量級的。雖然最終檢測的結(jié)果是沒有死鎖,但是這期間要消耗大量的CPU資源。因此,你就會看到CPU利用率很高,但是每秒?yún)s執(zhí)行不了幾個事務(wù)。

根據(jù)上面的分析,我們來討論一下,**怎么解決由這種熱點(diǎn)行更新導(dǎo)致的性能問題呢?**問題的癥結(jié)在于,死鎖檢測要耗費(fèi)大量的CPU資源。

  1. 一種頭痛醫(yī)頭的方法,就是如果你能確保這個業(yè)務(wù)一定不會出現(xiàn)死鎖,可以臨時把死鎖檢測關(guān)掉。但是這種操作本身帶有一定的風(fēng)險,因?yàn)闃I(yè)務(wù)設(shè)計(jì)的時候一般不會把死鎖當(dāng)做一個嚴(yán)重錯誤,畢竟出現(xiàn)死鎖了,就回滾,然后通過業(yè)務(wù)重試一般就沒問題了,這是業(yè)務(wù)無損的。而關(guān)掉死鎖檢測意味著可能會出現(xiàn)大量的超時,這是業(yè)務(wù)有損的。

  2. 另一個思路是控制并發(fā)度。根據(jù)上面的分析,你會發(fā)現(xiàn)如果并發(fā)能夠控制住,比如同一行同時最多只有10個線程在更新,那么死鎖檢測的成本很低,就不會出現(xiàn)這個問題。一個直接的想法就是,在客戶端做并發(fā)控制。但是,你會很快發(fā)現(xiàn)這個方法不太可行,因?yàn)榭蛻舳撕芏?。我見過一個應(yīng)用,有600個客戶端,這樣即使每個客戶端控制到只有5個并發(fā)線程,匯總到數(shù)據(jù)庫服務(wù)端以后,峰值并發(fā)數(shù)也可能要達(dá)到3000。因此,這個并發(fā)控制要做在數(shù)據(jù)庫服務(wù)端。如果你有中間件,可以考慮在中間件實(shí)現(xiàn);如果你的團(tuán)隊(duì)有能修改MySQL源碼的人,也可以做在MySQL里面?;舅悸肪褪?,對于相同行的更新,在進(jìn)入引擎之前排隊(duì)。這樣在InnoDB內(nèi)部就不會有大量的死鎖檢測工作了。

可能你會問,如果團(tuán)隊(duì)里暫時沒有數(shù)據(jù)庫方面的專家,不能實(shí)現(xiàn)這樣的方案,能不能從設(shè)計(jì)上優(yōu)化這個問題呢

你可以考慮通過將一行改成邏輯上的多行來減少鎖沖突。還是以影院賬戶為例,可以考慮放在多條記錄上,比如10個記錄,影院的賬戶總額等于這10個記錄的值的總和。這樣每次要給影院賬戶加金額的時候,隨機(jī)選其中一條記錄來加。這樣每次沖突概率變成原來的1/10,可以減少鎖等待個數(shù),也就減少了死鎖檢測的CPU消耗。

這個方案看上去是無損的,但其實(shí)這類方案需要根據(jù)業(yè)務(wù)邏輯做詳細(xì)設(shè)計(jì)。如果賬戶余額可能會減少,比如退票邏輯,那么這時候就需要考慮當(dāng)一部分行記錄變成0的時候,代碼要有特殊處理。

總結(jié)

  1. 全局鎖主要用在邏輯備份過程中。對于全部是InnoDB引擎的庫,我建議你選擇使用–single-transaction參數(shù),對應(yīng)用會更友好。

  2. 表鎖一般是在數(shù)據(jù)庫引擎不支持行鎖的時候才會被用到的。如果你發(fā)現(xiàn)你的應(yīng)用程序里有l(wèi)ock tables這樣的語句,你需要追查一下,比較可能的情況是:

  3. 要么是你的系統(tǒng)現(xiàn)在還在用MyISAM這類不支持事務(wù)的引擎,那要安排升級換引擎;
    要么是你的引擎升級了,但是代碼還沒升級。我見過這樣的情況,最后業(yè)務(wù)開發(fā)就是把lock tables 和 unlock tables 改成 begin 和 commit,問題就解決了。

  4. MDL會直到事務(wù)提交才釋放,在做表結(jié)構(gòu)變更的時候,你一定要小心不要導(dǎo)致鎖住線上查詢和更新。

  5. MySQL的行鎖,涉及了兩階段鎖協(xié)議、死鎖和死鎖檢測這兩大部分內(nèi)容。其中,我以兩階段協(xié)議為起點(diǎn),和你一起討論了在開發(fā)的時候如何安排正確的事務(wù)語句。這里的原則/我給你的建議是:如果你的事務(wù)中需要鎖多個行,要把最可能造成鎖沖突、最可能影響并發(fā)度的鎖的申請時機(jī)盡量往后放。
    但是,調(diào)整語句順序并不能完全避免死鎖。所以我們引入了死鎖和死鎖檢測的概念,以及提供了三個方案,來減少死鎖對數(shù)據(jù)庫的影響。減少死鎖的主要方向,就是控制訪問相同資源的并發(fā)事務(wù)量。

問題1

備份一般都會在備庫上執(zhí)行,你在用–single-transaction方法做邏輯備份的過程中,如果主庫上的一個小表做了一個DDL,比如給一個表上加了一列。這時候,從備庫上會看到什么現(xiàn)象呢?
假設(shè)這個DDL是針對表t1的, 這里我把備份過程中幾個關(guān)鍵的語句列出來:

Q1:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;Q2:START TRANSACTION  WITH CONSISTENT SNAPSHOT;/* other tables */Q3:SAVEPOINT sp;/* 時刻 1 */Q4:show create table `t1`;/* 時刻 2 */Q5:SELECT * FROM `t1`;/* 時刻 3 */Q6:ROLLBACK TO SAVEPOINT sp;/* 時刻 4 *//* other tables */

在備份開始的時候,為了確保RR(可重復(fù)讀)隔離級別,再設(shè)置一次RR隔離級別(Q1);

啟動事務(wù),這里用 WITH CONSISTENT SNAPSHOT確保這個語句執(zhí)行完就可以得到一個一致性視圖(Q2);

設(shè)置一個保存點(diǎn),這個很重要(Q3);

show create 是為了拿到表結(jié)構(gòu)(Q4),然后正式導(dǎo)數(shù)據(jù) (Q5),回滾到SAVEPOINT sp,在這里的作用是釋放 t1的MDL鎖 (Q6。當(dāng)然這部分屬于“超綱”,上文正文里面都沒提到。

DDL從主庫傳過來的時間按照效果不同,打了四個時刻。題目設(shè)定為小表,我們假定到達(dá)后,如果開始執(zhí)行,則很快能夠執(zhí)行完成。

參考答案如下:

  1. 如果在Q4語句執(zhí)行之前到達(dá),現(xiàn)象:沒有影響,備份拿到的是DDL后的表結(jié)構(gòu)。

  2. 如果在“時刻 2”到達(dá),則表結(jié)構(gòu)被改過,Q5執(zhí)行的時候,報(bào) Table definition has changed, please retry transaction,現(xiàn)象:mysqldump終止;

  3. 如果在“時刻2”和“時刻3”之間到達(dá),mysqldump占著t1的MDL讀鎖,binlog被阻塞,現(xiàn)象:主從延遲,直到Q6執(zhí)行完成。

  4. 從“時刻4”開始,mysqldump釋放了MDL讀鎖,現(xiàn)象:沒有影響,備份拿到的是DDL前的表結(jié)構(gòu)。

問題2

如果你要刪除一個表里面的前10000行數(shù)據(jù),有以下三種方法可以做到,但是那個更好些:

第一種,直接執(zhí)行delete from T limit 10000; 第二種,在一個連接中循環(huán)執(zhí)行20次 delete from T limit 500;第三種,在20個連接中同時執(zhí)行 delete from T limit 500。

方案一:事務(wù)相對較長,則占用鎖的時間較長,會導(dǎo)致其他客戶端等待資源時間較長。
方案二:串行化執(zhí)行,將相對長的事務(wù)分成多次相對短的事務(wù),則每次事務(wù)占用鎖的時間相對較短,其他客戶端在等待相應(yīng)資源的時間也較短。這樣的操作,同時也意味著將資源分片使用(每次執(zhí)行使用不同片段的資源),可以提高并發(fā)性。
方案三:人為自己制造鎖競爭,加劇并發(fā)量。

到此,關(guān)于“MySQL全局鎖、表鎖和行鎖的概念”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

網(wǎng)站名稱:MySQL全局鎖、表鎖和行鎖的概念
文章路徑:http://muchs.cn/article4/jcghoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、App設(shè)計(jì)、動態(tài)網(wǎng)站、外貿(mào)建站、域名注冊網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)