MySQL鎖機制總結(二)


前言:

Mysql是一個支持插件式存儲引擎的數據庫系統,本文討論的鎖機制也主要包含兩部分SERVER層的鎖和存儲引擎的鎖,存儲引擎是指innodb,其它存儲引暫不討論。              

1. 數據庫中鎖相關的基本概念

1)  樂觀鎖,悲觀鎖

      樂觀鎖和悲觀鎖都是一種並發控制策略。悲觀鎖假定多個事務會同時訪問同一個資源,采用的策略是“先上鎖,后訪問”,這種策略會有死鎖的風險。樂觀鎖相對於悲觀鎖而言,假定多個事務在運行過程中不會相互影響,寫入在讀取和寫入記錄時,不上鎖,取而代之是產生一個時間戳或版本號,事務提交階段,檢查記錄的版本號是否有被修改(若修改,則表示有其他事務讀寫),確定是否需要回滾事務。目前在數據庫領域,幾乎所有的DBMS都是采用悲觀鎖機制。

2)  MVCC(Multi-Version Concurrency Control)

      MVCC也是一種並發控制方法,MVCC對悲觀鎖控制機制做了改進,通過冗余數據的歷史版本,達到“讀不上鎖,讀寫不沖突”的效果,提高了並發效果。MVCC主要作用於讀提交和可重復讀兩種隔離級別上。

3)  兩階段鎖協議

      所謂兩段鎖協議是指上鎖分為兩個階段,加鎖和解鎖階段,保證加鎖和解鎖階段不交錯。對於數據庫系統而言,事務開始時,處於加鎖階段;事務提交或rollback時,事務進入解鎖階段。只有滿足兩段鎖協議的數據庫系統,並發調度的事務才是可以串行化的。

4)  意向鎖

     意向鎖機制約定如果對一個節點加鎖,必需先對它的上一層節點加意向鎖。比如,對一個記錄加鎖之前,首先對該記錄所在的表加意向鎖。意向鎖主要包括IS和IX,他們與S和X的兼容關系不在這里贅述。意向鎖的主要作用在於提高表鎖和行鎖沖突檢測效率。

5) 表鎖,記錄(行)鎖

      表鎖和記錄鎖是鎖系統里面最基本的鎖。分別用於鎖定表和記錄。對於表而言,根據情況可以有S,X,IS和IX四種鎖類別;對表上IS和IX,表示需要讀記錄和寫記錄;記錄鎖則主要包括X鎖和S鎖。有關行鎖的實現,可以參考之前的文章,INNODB行鎖源碼學習

6) 字典鎖(metadata lock)

    字典鎖是保護元數據的一種鎖,主要為了防止DDL和DML沖突的情況。有關MDL的詳細介紹,可以參考之前的文章,MYSQL METADATA LOCK

7)  死鎖

    所謂死鎖是指兩個或多個事務,各自占有對方的期望獲得的資源,形成的循環等待,彼此無法繼續執行的一種狀態。 

2. 舉個栗子

   上面列了這么多種類的鎖,下面通過一個簡單的例子說明各種鎖是如何作用的,它們加鎖和釋放鎖的先后順序如何。這里假設隔離級別是RC,ID為主鍵。

beginupdate t3 set c1=1 where id=1; commit;

流程

執行語句

執行內容

字典鎖

行鎖/表鎖

1

Begin

 

釋放MDL

release_transactional_locks

釋放表鎖,行鎖

2

update t3 set c1=1 where id=1;

 

上字典鎖

GLOBAL:STATMENT

MDL_INTENTION_EXCLUSIVE

 

3

TABLE:TRANSACTION

MDL_SHARED_WRITE

 

4

上行鎖

 

LOCK_TABLE:IX

(table:t3)

5

 

LOCK_REC:X

(id=1)

6

執行更新

 

 

7

釋放MDL

GLOBAL:STATMENT

 

8

commit;

 

COMMIT

字典鎖

COMMIT: MDL_EXPLICIT

MDL_INTENTION_EXCLUSIVE

 

9

執行提交

 

 

10

釋放引擎鎖

 

lock_release

11

釋放MDL

 

COMMIT: MDL_EXPLICIT

MDL_INTENTION_EXCLUSIVE

 

12

release_transactional_locks

TABLE:TRANSACTION

 

      可以看到,第一行begin,表示開啟一個新事務,隱含提交會話的上一個事務,需要釋放之前的鎖。第2到7行是兩階段鎖中的上鎖階段,分別先后上了字典鎖、表的意向鎖和行鎖。上完鎖后,才開始真正的更新階段,從這里也可以看到MySQL的寫操作是符合悲觀鎖策略。第4行和第5行,我們可以看到意向鎖是如何運作的,上記錄id=1的行鎖之前,先對表t3上了意向鎖。第7行,語句執行完后,可以釋放STATEMENT級別的字典鎖,避免長時間持有鎖阻塞該表的DDL操作。8-12是提交階段,進入兩段鎖中的釋放鎖過程,先后釋放引擎層的表鎖和行鎖;然后釋放TRANSACTION級別的MDL鎖。

3. 常用語句加鎖分析

假設隔離級別:RC,id為主鍵

典型語句

SQL層面(MDL鎖)

存儲引擎

innodb

 

 

       范圍/對象

持有時間

表鎖

行鎖

SELECT操作

SELECT * FROM T

TABLE:

MDL_SHARED_READ

MDL_TRANSACTION

None

None

Show create table T

TABLE:

MDL_SHARED_HIGH_PRIO

MDL_TRANSACTION

 

 

LOCK TABLE T READ

TABLE:

MDL_SHARED_READ

MDL_TRANSACTION

None

None

LOCK TABLE T WRITE

GLOBAL:

MDL_INTENTION_EXCLUSIVE

MDL_STATEMENT

 

None

None

SCHEMA:

MDL_INTENTION_EXCLUSIVE

TABLE:

MDL_SHARED_NO_READ_WRITE

 

TRANSACTION

Flush table t with read lock

TABLE:

MDL_SHARED_NO_WRITE

TRANSACTION

None

None

Flush table with read lock

GLOBAL:

MDL_SHARED

 

MDL_EXPLICIT

None

None

COMMIT:

MDL_SHARED

 

MDL_EXPLICIT

DML操作

SELECT * FROM T FOR UPDATE;

Update T set c1=? Where id=?

GLOBAL:

MDL_INTENTION_EXCLUSIVE

MDL_STATEMENT

IX

X

TABLE:

MDL_SHARED_WRITE

TRANSACTION

 

DDL操作

Alter table t add column c1 int;

Truncate table t;

GLOBAL:

MDL_INTENTION_EXCLUSIVE

 

MDL_STATEMENT

None

X

SCHEMA:

MDL_INTENTION_EXCLUSIVE

TABLE:

MDL_EXCLUSIVE

TRANSACTION

 

COMMIT:

MDL_INTENTION_EXCLUSIVE

MDL_EXPLICIT

Set global read_only=1;

GLOBAL:

MDL_SHARED

COMMIT:

MDL_SHARED

MDL_EXPLICIT

 

None

 

None

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM