1. 程式人生 > 其它 >mysql (4):進階篇(下)

mysql (4):進階篇(下)

五 鎖

5.1 概述

鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。在資料庫中,除傳統的計算資源(CPU、RAM、I/O)的爭用以外,資料也是一種供許多使用者共享的資源。如何保證資料併發訪問的一致性、有效性是所有資料庫必須解決的一個問題,鎖衝突也是影響資料庫併發訪問效能的一個重要因素。從這個角度來說,鎖對資料庫而言顯得尤其重要,也更加複雜。
MySQL中的鎖,按照鎖的粒度分,分為以下三類:

  • 全域性鎖:鎖定資料庫中的所有表。
  • 表級鎖:每次操作鎖住整張表。
  • 行級鎖:每次操作鎖住對應的行資料。

5.2 全域性鎖

5.2.1 介紹

全域性鎖就是對整個資料庫例項加鎖,加鎖後整個例項就處於只讀狀態,後續的DML的寫語句,DDL語句,已經更新操作的事務提交語句都將被阻塞。
其典型的使用場景是做全庫的邏輯備份,對所有的表進行鎖定,從而獲取一致性檢視,保證資料的完整性。

為什麼全庫邏輯備份,就需要加全就鎖呢?
A. 我們一起先來分析一下不加全域性鎖,可能存在的問題。
假設在資料庫中存在這樣三張表: tb_stock 庫存表,tb_order 訂單表,tb_orderlog 訂單日誌表。

1.在進行資料備份時,先備份了tb_stock庫存表。
2.然後接下來,在業務系統中,執行了下單操作,扣減庫存,生成訂單(更新tb_stock表,插入tb_order表)。
3.然後再執行備份 tb_order表的邏輯。
4.業務中執行插入訂單日誌操作。
5.最後,又備份了tb_orderlog表。

此時備份出來的資料,是存在問題的。因為備份出來的資料,tb_stock表與tb_order表的資料不一致(有最新操作的訂單資訊,但是庫存數沒減)。
那如何來規避這種問題呢? 此時就可以藉助於MySQL的全域性鎖來解決。
B. 再來分析一下加了全域性鎖後的情況

對資料庫進行進行邏輯備份之前,先對整個資料庫加上全域性鎖,一旦加了全域性鎖之後,其他的DDL、DML全部都處於阻塞狀態,但是可以執行DQL語句,也就是處於只讀狀態,而資料備份就是查詢操作。那麼資料在進行邏輯備份的過程中,資料庫中的資料就是不會發生變化的,這樣就保證了資料的一致性和完整性。

5.2.2 語法
1). 加全域性鎖
flush tables with read lock ;

2). 資料備份
mysqldump -uroot –p1234 itcast > itcast.sql
資料備份的相關指令, 在後面MySQL管理章節, 還會詳細講解.

3). 釋放鎖
unlock tables ;

5.2.3 特點

資料庫中加全域性鎖,是一個比較重的操作,存在以下問題:

  • 如果在主庫上備份,那麼在備份期間都不能執行更新,業務基本上就得停擺。
  • 如果在從庫上備份,那麼在備份期間從庫不能執行主庫同步過來的二進位制日誌(binlog),會導致主從延遲
    在InnoDB引擎中,我們可以在備份時加上引數 --single-transaction 引數來完成不加鎖的一致性資料備份。
mysqldump --single-transaction -uroot –p123456 itcast > itcast.sql

5.3 表級鎖

5.3.1 介紹

表級鎖,每次操作鎖住整張表。鎖定粒度大,發生鎖衝突的概率最高,併發度最低。應用在MyISAM、InnoDB、BDB等儲存引擎中。
對於表級鎖,主要分為以下三類:

  • 表鎖
  • 元資料鎖(meta data lock,MDL)
  • 意向鎖

5.3.2 表鎖

對於表鎖,分為兩類:

  • 表共享讀鎖(read lock)
  • 表獨佔寫鎖(write lock)

語法:
加鎖:lock tables 表名 read/write
釋放鎖:unlock tables 客戶端斷開連線
特點:
特點:
A. 讀鎖

左側為客戶端一,對指定表加了讀鎖,不會影響右側客戶端二的讀,但是會阻塞右側客戶端的寫。
測試:

B. 寫鎖

左側為客戶端一,對指定表加了寫鎖,會阻塞右側客戶端的讀和寫。
測試:

結論: 讀鎖不會阻塞其他客戶端的讀,但是會阻塞寫。寫鎖既會阻塞其他客戶端的讀,又會阻塞其他客戶端的寫。

5.3.3 元資料鎖

meta data lock , 元資料鎖,簡寫MDL。
MDL加鎖過程是系統自動控制,無需顯式使用,在訪問一張表的時候會自動加上。MDL鎖主要作用是維護表元資料的資料一致性,在表上有活動事務的時候,不可以對元資料進行寫入操作。為了避免DML與DDL衝突,保證讀寫的正確性。

這裡的元資料,大家可以簡單理解為就是一張表的表結構。 也就是說,某一張表涉及到未提交的事務時,是不能夠修改這張表的表結構的。

在MySQL5.5中引入了MDL,當對一張表進行增刪改查的時候,加MDL讀鎖(共享);當對錶結構進行變更操作的時候,加MDL寫鎖(排他)。

常見的SQL操作時,所新增的元資料鎖:

對應SQL 鎖型別 說明
lock tables xxx read /write SHARED_READ_ONLY / SHARED_NO_READ_WRITE
select 、select ...lock in share mode SHARED_READ 與SHARED_READ、SHARED_WRITE相容,與EXCLUSIVE互斥
insert 、update、delete、select ... for update SHARED_WRITE 與SHARED_READ、SHARED_WRITE相容,與EXCLUSIVE互斥
alter table ... EXCLUSIVE 與其他的MDL都互斥

演示:
當執行SELECT、INSERT、UPDATE、DELETE等語句時,新增的是元資料共享鎖(SHARED_READ / SHARED_WRITE),之間是相容的。

當執行SELECT語句時,新增的是元資料共享鎖(SHARED_READ),會阻塞元資料排他鎖(EXCLUSIVE),之間是互斥的。

我們可以通過下面的SQL,來檢視資料庫中的元資料鎖的情況:

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks ;

我們在操作過程中,可以通過上述的SQL語句,來檢視元資料鎖的加鎖情況。

5.3.4 意向鎖

1). 介紹
為了避免DML在執行時,加的行鎖與表鎖的衝突,在InnoDB中引入了意向鎖,使得表鎖不用檢查每行資料是否加鎖,使用意向鎖來減少表鎖的檢查。

假如沒有意向鎖,客戶端一對錶加了行鎖後,客戶端二如何給表加表鎖呢,來通過示意圖簡單分析一下:
首先客戶端一,開啟一個事務,然後執行DML操作,在執行DML語句時,會對涉及到的行加行鎖。

當客戶端二,想對這張表加表鎖時,會檢查當前表是否有對應的行鎖,如果沒有,則新增表鎖,此時就會從第一行資料,檢查到最後一行資料,效率較低。

有了意向鎖之後 :
客戶端一,在執行DML操作時,會對涉及的行加行鎖,同時也會對該表加上意向鎖。

而其他客戶端,在對這張表加表鎖的時候,會根據該表上所加的意向鎖來判定是否可以成功加表鎖,而不用逐行判斷行鎖情況了。

2). 分類

  • 意向共享鎖(IS): 由語句select ... lock in share mode新增 。 與 表鎖共享鎖(read)相容,與表鎖排他鎖(write)互斥。
  • 意向排他鎖(IX): 由insert、update、delete、select...for update新增 。與表鎖共享鎖(read)及排他鎖(write)都互斥,意向鎖之間不會互斥。

一旦事務提交了,意向共享鎖、意向排他鎖,都會自動釋放。

可以通過以下SQL,檢視意向鎖及行鎖的加鎖情況:

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;

演示:
A. 意向共享鎖與表讀鎖是相容的

B. 意向排他鎖與表讀鎖、寫鎖都是互斥的

5.4 行級鎖

5.4.1 介紹