欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解MySQL的并發(fā)控制

 更新時間:2023年05月27日 10:56:24   作者:_BugMan  
無論何時只要有多個查詢需要在同一時刻修改數(shù)據(jù),都會產(chǎn)生并發(fā)控制問題,MySQL可以在兩個層面進行并發(fā)控制,服務器層和存儲引擎層,下面這篇文章主要給大家介紹了關于MySQL并發(fā)控制的相關資料,需要的朋友可以參考下

1.概述

所謂的并發(fā)控制,就是規(guī)避多個會話并發(fā)訪問數(shù)據(jù)庫帶來的諸如臟數(shù)據(jù)之類的數(shù)據(jù)一致性問題,MySQL中提供了一系列的機制讓我們可以去進行并發(fā)控制。

本質(zhì)上來說MySQL就是用的兩種鎖來進行并發(fā)控制,一種是表鎖,鎖住整張表;一種是行鎖,鎖住某個數(shù)據(jù)行。

平時我們使用的時候,很少會直接去操作鎖,因為MySQL已經(jīng)幫我們封裝的很好了,直接用innodb引擎+事務就能很好的進行并發(fā)控制,事務底層其實依賴的就是行鎖。

本文會先聊事務、再聊表鎖、行鎖,但其實總的來說MySQL進行并發(fā)控制,就是行鎖和表鎖,事務的底層用的就是行鎖,只是事務太重要了所以單獨拎出來作為一個獨立的章節(jié)聊。

2.事務

2.1.什么是事務

注意:只有innodb引擎是支持事務的,所以本文與事務相關的討論,默認都是在innodb引擎下。

在實際使用中,會存在這樣一類場景,我們希望幾條SQL要么同時執(zhí)行成功,要么同時失敗,不能有的成功,有的失敗。

比如網(wǎng)購下單,生成訂單、扣減庫存兩條SQL,必須保證要么全部成功,要么全部失敗,不能說生成訂單成功,但是扣減庫存失敗了,或者說扣減庫存成功但是生成訂單失敗了,以上任何一種情況都是會產(chǎn)生臟數(shù)據(jù)的。如果兩者中有一者失敗,另外一個也需要跟著執(zhí)行不成功,從而保證數(shù)據(jù)的正確性。

事務就是為了滿足將多條捆綁在一起,同成功,同失敗而出現(xiàn)的。人們在實現(xiàn)事務過程中,發(fā)現(xiàn)事務要實現(xiàn)上面我們說的效果,那么就必須實現(xiàn)四點:

  • 原子性(Atomicity)
  • 一致性(Consistent)
  • 隔離性(Isolation)
  • 持久性(Durable)

也就是大名鼎鼎的ACID,很多地方稱其為事務的四大特性。

1.原子性:

事務是一個原子操作單元,其對數(shù)據(jù)的修改,要么全部執(zhí)行,要么全部不執(zhí)行。

2.一致性:

數(shù)據(jù)庫中的數(shù)據(jù)總是從一個狀態(tài)到另一個狀態(tài),不能存在中間狀態(tài)。繼續(xù)以網(wǎng)購下單為例,一開始的數(shù)據(jù)庫中的數(shù)據(jù)為A狀態(tài),執(zhí)行完事務,扣減庫存、新增訂單后的數(shù)據(jù)狀態(tài)為B狀態(tài),數(shù)據(jù)庫只能由A到B,不能出現(xiàn)諸如扣了庫存,沒生成訂單,或者生成了訂單,沒扣庫存這樣的中間狀態(tài)。

3.隔離性:

一個事務在提交之前,其所做的修改對其它事務來說是不可見的。不保證隔離性會產(chǎn)生臟數(shù)據(jù),這個很好理解,舉個例子:

A的銀行賬戶有400,有兩個事務,彼此之間數(shù)據(jù)可見,也就是一個事務修改數(shù)據(jù),不管提沒提交其他事務都看得見。

事務1,A向B轉200:

  • A的賬戶扣減200
  • B的賬戶新增200

事務2,A向C轉200:

  • A的賬戶扣減200
  • C的賬戶新增200

如果在事務1中的1、2步的時間間隙內(nèi)事務2間插執(zhí)行完畢,那么在事務1第2步執(zhí)行前A的賬戶中已經(jīng)被扣減了兩次200,余額為0,C的賬戶中多了200。

這時候如果在事務1的第2步中出錯了、回滾,那么A的賬戶又會回到事務1第一步執(zhí)行之前的狀態(tài),也就是A的賬戶又恢復成了400。最后C的賬戶平白無故多了200。

4.持久性:

事務完成后,其對數(shù)據(jù)的修改是永久的,即使系統(tǒng)斷電、重啟,也不會變。

2.2.事務的隔離級別

2.2.1.三種數(shù)據(jù)一致性問題

在沒有隔離性的情況下,事物之間會出現(xiàn)3種數(shù)據(jù)一致性問題:

  • 臟讀:事務A讀取了事務B更新的數(shù)據(jù),然后B回滾操作,那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)
  • 不可重復讀:事務 A 多次讀取同一數(shù)據(jù),事務 B 在事務A多次讀取的過程中,對數(shù)據(jù)作了更新并提交,導致事務A多次讀取同一數(shù)據(jù)時,結果 不一致。
  • 幻讀:系統(tǒng)管理員A將數(shù)據(jù)庫中所有學生的成績從具體分數(shù)改為ABCDE等級,但是系統(tǒng)管理員B就在這個時候插入了一條具體分數(shù)的記錄,當系統(tǒng)管理員A改結束后發(fā)現(xiàn)還有一條記錄沒有改過來,就好像發(fā)生了幻覺一樣,這就叫幻讀。

2.2.2.四種隔離級別

隔離級別可理解為,隔離性的嚴格度,MySQL并不是固定死了各個事務間就是不可讀的,而是規(guī)定了各種強度的隔離級別。

觀察上面3種數(shù)據(jù)一致性問題就會發(fā)現(xiàn),解決它們需要的隔離性是遞增的,MySQL一共給出4種隔離級別,隔離性也是遞增的,對應解決以上3個問題,有3種,加上1種3種問題都能覆蓋解決的:

  1. Read Uncommitted(讀未提交):最低的隔離級別,允許一個事務讀取另一個事務尚未提交的數(shù)據(jù)變更??赡軐е屡K讀(Dirty Read)問題。
  2. Read Committed(讀已提交):確保一個事務只能讀取另一個事務已經(jīng)提交的數(shù)據(jù)變更。防止臟讀問題,但可能導致不可重復讀(Non-repeatable Read)問題。
  3. Repeatable Read(可重復讀):確保在同一個事務中多次讀取同一數(shù)據(jù)時,能夠得到一致的結果。防止臟讀和不可重復讀問題,但可能導致幻讀(Phantom Read)問題。
  4. Serializable(串行化):最高的隔離級別,強制事務串行執(zhí)行,確保不會發(fā)生臟讀、不可重復讀和幻讀問題。但是并發(fā)性能較差,通常不建議在高并發(fā)環(huán)境中使用。

2.3.如何設置隔離級別

可以在連接字符串中設置隔離級別:

jdbc:mysql://localhost/mydatabase?useSSL=false&characterEncoding=utf8&transactionIsolation=隔離級別

可以通過SQL在會話中設置隔離級別:

SET TRANSACTION ISOLATION LEVEL 隔離級別;

3.鎖

3.1.鎖與事務的關系

鎖是計算機協(xié)調(diào)多個進程或線程并發(fā)訪問某一資源的機制,用來解決并發(fā)訪問帶來的數(shù)據(jù)一致性問題。在數(shù)據(jù)庫中,除傳統(tǒng)的計算資源(如CPU、IO、RAM)的爭用以外,數(shù)據(jù)更是會被并發(fā)訪問的資源。所以MySQL數(shù)據(jù)庫也用鎖機制來保證數(shù)據(jù)并發(fā)訪問的一致性。

不同的隔離級別底層就是用不同的鎖來實現(xiàn)的。

3.2.分類

MySQL的鎖可以從兩種維度來分,

一個維度是按照鎖的是一行,還是鎖的是整張表,分為:

  • 行鎖
  • 表鎖

另一個維度是按照鎖的操作是讀操作,還是寫操作,分為:

  • 讀鎖
  • 寫鎖

3.3.表鎖

3.3.1.概述

MySQL中innodb引擎和myisam引擎均支持用lock tables指令來鎖表。

3.3.2.讀鎖

讀鎖,一種共享鎖,針對被鎖表,所有會話都可以進行讀操作,所有會話都無法進行寫操作。加鎖方和其他客戶端的區(qū)別是,加鎖方直接不允許進行寫操作,而其他會話的寫操作允許進行,只是會被阻塞掛起。鎖解開后,所有掛起的操作線程會去重新爭搶資源。

加鎖指令:

lock tables 表名 read;

釋放鎖指令:

unlock tanles;

加鎖方不允許進行寫操作:

其它客戶端的寫操作在加鎖方釋放鎖之前都被掛起:

3.3.3.寫鎖

寫鎖,排它鎖,針對被鎖表,加鎖方可以讀寫,其他會話的寫操作會直接失敗,讀操作會被阻塞掛起,解鎖以后,被掛起的線程會重新去爭搶資源。

加鎖指令:

lock tables 表名 write;

其它會話的讀操作、寫操作在加鎖方釋放鎖之前都被阻塞掛起:

 

3.3.4.保護機制

讀鎖、寫鎖中,加鎖方都只能讀當前被自己鎖定的表,這是MySQL的一個保護機制,為的就是強制要求加鎖方給出一個說法,到底準備鎖多久,不給說法不讓走。

3.4.行鎖

3.4.1.概述

innodb和myIsam最大的不同有兩點,一是支持事務,二是支持行級鎖。

3.4.2.什么是MVCC

行鎖沒有顯式的聲明辦法,而是藏在默認實現(xiàn)中,MVCC 是 MySQL InnoDB 存儲引擎的默認并發(fā)控制機制,其采用的就是表鎖。

并發(fā)控制有幾種處理方法,

第一種: 基于鎖的并發(fā)控制,程序員B開始修改數(shù)據(jù)時,給這些數(shù)據(jù)加上鎖,程序員A這時再讀,就發(fā)現(xiàn)讀取不了,處于等待情況,只能等B操作完才能讀數(shù)據(jù),這保證A不會讀到一個不一致的數(shù)據(jù),但是這個會影響程序的運行效率。

第二種:MVCC,每個用戶連接數(shù)據(jù)庫時,看到的都是某一特定時刻的數(shù)據(jù)庫快照,在B的事務沒有提交之前,A始終讀到的是某一特定時刻的數(shù)據(jù)庫快照,不會讀到B事務中的數(shù)據(jù)修改情況,直到B事務提交,才會讀取B的修改內(nèi)容。

MVCC其實就是實現(xiàn)事務的關鍵,后續(xù)會有文章專門深入聊事務的實現(xiàn),此處暫不展開。

3.4.3.mvcc的使用

首先有一個需要糾正的是,很多地方都說mvcc是通過手動提交來觸發(fā)的,這是個誤導,不管手動提交還是自動提交MVCC機制都是生效的,只是手動提交用來觀察mvcc過程更加直觀。

此處為了直觀,我們也以手動提交為例,首先通過set  autocommit=0可以關閉自動提交。關閉后每次執(zhí)行sql以后,通過commit命令來手動提交,才會對數(shù)據(jù)庫產(chǎn)生影響,否則只會對當前操作方的數(shù)據(jù)快照有影響。innodb引擎中,其他客戶端想查看到最新的數(shù)據(jù)情況也必須通過commit指令來做一次同步(因為innodb默認隔離級別為可重復讀)。

當一個會話修改某行數(shù)據(jù),未commit前,其他會話對該行數(shù)據(jù)的修改會阻塞掛起,直到先改那個會話commit為止。

3.4.4.間隙鎖

使用范圍條件匹配時,innodb會給符合條件的已有數(shù)據(jù)記錄的索引加“范圍鎖”(范圍鎖是特殊的行鎖),對于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做間隙(GAP),innodb也會對這個間隙加鎖,這種機制叫做“間隙鎖”。

3.4.5.行鎖變表鎖 

任何需要全表掃描的情況時,行鎖都會升級為表鎖。

因為MySQL不知道到底該鎖哪行,所以會將整個表都鎖起來,然后再進行全表掃描。

全表掃描的情況無非兩種:

  • 沒建索引。
  • 索引失效。

總結

到此這篇關于MySQL并發(fā)控制的文章就介紹到這了,更多相關MySQL并發(fā)控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論