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

MySQL中的鎖概念

Mysql中不一樣的存儲引擎支持不一樣的鎖機制。好比MyISAM和MEMORY存儲引擎採用的表級鎖,BDB採用的是頁面鎖,也支持表級鎖,InnoDB存儲引擎既支持行級鎖,也支持表級鎖,默認狀況下采用行級鎖。java

Mysql3中鎖特性以下:mysql

表級鎖:開銷小,加鎖塊;不會出現死鎖,鎖定粒度大,發生鎖衝突的機率最高,併發度最低。面試

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

頁面鎖:開銷和加鎖界於表鎖和行鎖之間,會出現死鎖;鎖定粒度界與表鎖和行鎖之間,併發通常。sql

MyISAM表索

1.查詢表級鎖爭用狀況

經過檢查table_locks_waited和table_locks_immediate狀態變量分析系統上表鎖爭奪狀況數據庫


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

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數據結果不是在同一個時間點上。
正確的作法是:
lock table t1 read, t2 read;select count(t1.id1) as 'sum' from t1;select count(t2.id1) as 'sum' from t2;unlock tables;複製代碼

固然也可以使用union,這樣寫:
SELECT   COUNT(t1.`id1`) AS dadasum,'t1' AS tablenameFROM  t1UNIONALL SELECT   COUNT(t2.`id1`)AS dadasum ,'t2' AS tablenameFROM  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 * FROM table_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) DEFAULT NULL,  `id2` int(3) unsigned zerofill NOT NULL DEFAULT '000') ENGINE=InnoDB DEFAULT CHARSET=utf8複製代碼
<span style="font-size:18px;">insert into t1 valuses(1,1),(2,2);</span>
複製代碼


由於沒有建立索引,當給第一個會話添加索引時候,其實添加的是表索引,而非行索引,由於第二會話在查詢其餘信息時候,一直處於等待狀態,最後超時,直到第一個會話事務提交後,方可查詢。(須要先設置 set autocommit=0)
實例二:
修改上面t1表中數據,數據以下

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


有此能夠看出此時,mysql使用的是行索引。
可是還有一個須要咱們注意

很明顯兩個會話查詢的不是同一行記錄,爲何會話2仍然須要等待會話1提交以後才能查詢呢?仍是由於Mysql行鎖是針對索引加的鎖,不是針對記錄加的鎖,索引雖然訪問不一樣的記錄,可是他們的索引相同,是會出現衝突的,在設計數據庫時候須要注意這一點。上面只有將字段id2,也添加上索引才能解決衝突問題。這也是mysql效率低的一個緣由。

工做一到五年的java 開發工程師朋友能夠加入咱們Java架構交流羣:760940986 羣內提供 高可用,高併發,spring源碼,mybatis源碼,JVM,大數據,Netty等多個技術知識的架構視頻資料 還有大把大牛在羣內交流以及解答面試指導,問題答疑~~要進來和大牛交流學習提高提高本身嗎~~~~ 
mybatis

加羣能夠獲取一份人生職業規劃思惟導圖以及進階架構師必備視頻資料~架構

相關文章
相關標籤/搜索