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. 意向排他鎖與表讀鎖、寫鎖都是互斥的