MySQL數據庫鎖機制之MyISAM引擎表鎖和InnoDB行鎖詳解

有此可以看出此時,mysql使用的是行索引。

但是還有一個需要我們注意

MySQL中的鎖概念

Mysql中不同的存儲引擎支持不同的鎖機制。比如MyISAM和MEMORY存儲引擎采用的表級鎖,BDB采用的是頁面鎖,也支持表級鎖,InnoDB存儲引擎既支持行級鎖,也支持表級鎖,默認情況下采用行級鎖。

Mysql3中鎖特性如下:

表級鎖:開銷小,加鎖塊;不會出現死鎖,鎖定粒度大,發生鎖沖突的概率最高,并發度最低。

行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,并發性也最高。

頁面鎖:開銷和加鎖界于表鎖和行鎖之間,會出現死鎖;鎖定粒度界與表鎖和行鎖之間,并發一般。

MyISAM表索

1.查詢表級鎖爭用情況

通過檢查table_locks_waited和table_locks_immediate狀態變量分析系統上表鎖爭奪情況

table_locks_waited鎖定等待時間越長,則說明存在較嚴重的表級別鎖爭用情況。

2.鎖模式

mysql的表鎖有兩種模式:表共享讀鎖(table read lock)和表獨占寫鎖(table write lock)

說明 1.myISAM表的讀操作,不會阻塞其他用戶對同一個表的讀請求,但會阻塞對同一個表的寫請求。

?2.myISAM表的寫操作,會阻塞其他用戶對同一個表的讀和寫操作。

? ? ? ? 3.myISAM表的讀、寫操作之間、以及寫操作之間是串行的。

實例如下,打開了兩個會話,當t3處于讀鎖定時候,會話二可以檢索t3數據。當t3處于寫鎖定時候,會話二只有等到解鎖后,才能顯示數據(可以對比檢索時間)。

3.加表鎖

MyISAM在執行查詢前,會自動執行表的加鎖、解鎖操作,一般情況下不需要用戶手動加、解鎖,但是有的時候也需要顯示加鎖。

比如:檢索某一個時刻t1,t2表中數據數量。

常用代碼如下:

select count(t1.id1) as 'sum' from t1;

select count(t2.id1) as 'sum' from t2;

其實這是不正確的,很有可能當你在檢索t1的那個時間點,t2的數據已經發生了變化,也就是說你檢查出的t1和t2數據結果不是在同一個時間點上。

正確的做法是:

locktablet1read, t2read;

selectcount(t1.id1)as'sum'fromt1;

selectcount(t2.id1)as'sum'fromt2;

unlocktables;

當然也可使用union,這樣寫:

SELECT

COUNT(t1.`id1`)ASdadasum,'t1'AStablename

FROM

? t1

UNION

ALL

SELECT

COUNT(t2.`id1`)ASdadasum ,'t2'AStablename

FROM

? t2 ;

注意事項

1.在鎖定表時候,如果加上關鍵字local,滿足myISAM表的并發插入問題。eg: lock table t3 read local;

2.使用locak tables 給表加鎖時候,必須同時給所有涉及到的表加鎖,因為加鎖之后,當前會話,就不能操作沒有加鎖的表。

4.并發插入問題

myISAM存儲引擎有一個系統變量,concurrent_insert,專門用來控制并發插入行為的,值可以為0,1,2.

concurrent_insert為0時候,不允許插入

concurrent_insert為1時候,如果mysql沒有空洞(中間沒有被刪除的行),myISAM運行一個進程讀表的時候,另一個進程從表尾插入記錄,這也是mysql默認設置。

concurrent_insert為2時候,無論MyISAM表中有沒有空洞,都允許在表尾并行的插入。

5.myISAM鎖調度問題

MyISAM存儲引擎的讀鎖和寫鎖是互斥的,讀寫操作室串行的,那么如果讀寫兩個進程同時請求同一張表,Mysql將會使寫進程先獲得鎖。不僅僅如此,即使讀請求先到達鎖等待隊列,寫鎖后到達,寫鎖也會先執行。因為mysql因為寫請求比讀請求更加重要。這也正是MyISAM不適合含有大量更新操作和查詢操作應用的原因。

調節辦法:

1)通過指定啟動參數low-priority-updates,使MyISAM引擎默認給與讀請求優先的權限

2)通過執行set low_PRIORITY_UPDATES=1,降低更新請求的優先級。

3)指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性。

InnoDB鎖

1.InnoDB與MyISAM最大不同有兩點:

?1).支持事務

?2).采用行級鎖

2.查看InnoDB行鎖爭用情況

3.innodb行鎖模式以及加鎖方法

innoDB實現了以先兩種類型的行鎖:

共享鎖(S):允許一個事務去讀一行,阻止其他事務獲取相同數據集的排他鎖。

排他鎖(X):允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的共享讀鎖和排他寫鎖。

先兩種意向表鎖:

意向同享鎖

意向排他鎖

如果一個事務請求的鎖模式與當前的鎖模式兼容,innodb就將請求的鎖授予該事務;反之,如果兩者不兼容,該事務就要等待鎖釋放。意向鎖是Innodb自動加的,不需要用戶干預。對于UPDATE、DELETE、INSERT語句,Innodb會自動給涉及的數據集加排他鎖(X);對于普通SELECT語句,Innodb不會加任何鎖。

顯示添加鎖

共享鎖(S) : SELECT * FROM table_name WHERE .... LOCK IN SHARE MODE

排他鎖(X): ?SELECT * FROMtable_name WHERE .... FOR UPDATE.

使用select ... in share mode獲取共享鎖,主要用在需要數據依存關系時,確認某行記錄是否存在,并確保沒有人對這個記錄進行update或者delete。

4.InnoDB行鎖實現方式

InnoDB行鎖是通過給索引上的索引項加鎖來實現的,這一點MySQL與Oracle不同,后者是通過再數據塊中,對相應數據行加鎖來實現的。InnoDB這種行鎖實現特點意味著:只有通過索引條件檢索數據,innoDB才使用行級鎖,否則InnoDB將使用表鎖,在實際開發中應當注意。

實例一:

建立t1表如下:

CREATE

TABLE`t1`(

`id1`int(5)DEFAULTNULL,

`id2`int(3)unsignedzerofillNOTNULLDEFAULT'000'

)ENGINE=InnoDBDEFAULTCHARSET=utf8

insertintot1 valuses(1,1),(2,2);

因為沒有創建索引,當給第一個會話添加索引時候,其實添加的是表索引,而非行索引,因為第二會話在查詢其他信息時候,一直處于等待狀態,最后超時,直到第一個會話事務提交后,方可查詢。(需要先設置 set autocommit=0)

實例二:

修改上面t1表中數據,數據如下

給id1添加索引ALTER TABLE t1 ADD INDEX id1(id1);

有此可以看出此時,mysql使用的是行索引。

但是還有一個需要我們注意很明顯兩個會話查詢的不是同一行記錄,為什么會話2仍然需要等待會話1提交之后才能查詢呢?還是因為Mysql行鎖是針對索引加的鎖,不是針對記錄加的鎖,索引雖然訪問不同的記錄,但是他們的索引相同,是會出現沖突的,在設計數據庫時候需要注意這一點。上面只有將字段id2,也添加上索引才能解決沖突問題。這也是mysql效率低的一個原因。

參考:《MySQL數據庫開發、優化與管理維護》

Java高架構師、分布式架構、高可擴展、高性能、高并發、性能優化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式項目實戰學習架構師視頻免費學習加群:835638062 點擊鏈接加入群聊【Java高級架構】:https://jq.qq.com/?_wv=1027&k=5S3kL3v

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容