一. MySQL的鎖粒度
按鎖的粒度分,MySQL的鎖可以分為三類:
- 行級鎖:加鎖開銷最大,且有可能出現(xiàn)死鎖,但并發(fā)度也最高。分為共享鎖和排他鎖(InnoDB默認)
- 表級鎖:即為整張表加鎖,開銷小,加鎖快,且不會出現(xiàn)死鎖,但并發(fā)度較低。分為表共享讀鎖和表獨占寫鎖(MyISAM默認,InnoDB)。
- 頁級鎖:加鎖開銷和并發(fā)度介于上述二者之間,且會出現(xiàn)死鎖(BDB默認)
二. MyISAM表鎖
1. 分類
MyISAM的表鎖分為表共享讀鎖和表獨享寫鎖,我們在執(zhí)行select操作時會自動加表共享讀鎖,在執(zhí)行寫操作(update,insert,delete)時會自動加表獨享寫鎖,但我們也可以用下面的方式顯式的獲取鎖,尤其是我們要對多個表進行同步的時候:
(1)給t1加寫鎖:
lock table t1 write;
unlock tables; //釋放鎖
(2)給t1,t2加讀鎖:
lock tables t1 read local, t2 read local; //local是為了允許在表尾并發(fā)插入記錄,因為MyISAM默認是串行的。
//do something
unlock tables;
(3)通過別名訪問:
lock table t1 read;
select a.name from t1 a where id=1; //會報錯:table a was not locked with lock tables
正確的加鎖方式:
lock table t1 as a read;
此外,在InnoDB引擎中,如果查詢操作沒有可用的索引也會使用表級鎖,因為需要對全表進行掃描。
2. MyISAM的鎖調(diào)度
之前說過MyISAM的讀鎖和寫鎖是互斥的,讀寫操作是串行的,但是假如有一個讀請求和寫請求同時請求鎖,那么MySQL會使寫請求先獲得鎖,此外假如有很多讀寫請求排隊獲取鎖,那么MySQL也會把寫請求安排在讀請求前面,因為MySQL認為寫請求比讀請求重要,而這種設(shè)定不適用于讀請求很重要的場景,比如登錄系統(tǒng)等,且有可能會造成讀請求長時間得不到響應(yīng)的情況,但我們可以通過設(shè)置來調(diào)節(jié)MyISAM的調(diào)度:
通過設(shè)定啟動參數(shù)low-priority-updates,使MyISAM引擎默認給予讀請求較高的優(yōu)先級
通過執(zhí)行SET LOW_PRIORITY_UPDATES=1,使該連接的更新請求優(yōu)先級降低
通過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,降低該語句的優(yōu)先級
三. InnoDB鎖問題
1. InnoDB中的行鎖與表鎖
(1)只有通過索引條件檢索數(shù)據(jù)才會使用行級鎖,
(2)行鎖是對索引加鎖而非是對數(shù)據(jù)加鎖,這意味著即使是不同的數(shù)據(jù)行,但是如果索引相同,也可能會出現(xiàn)鎖沖突。
(3)即使是使用索引字段檢索數(shù)據(jù),也不保證會使用索引;如果MySQL認為全表掃描的代價更低(比如有些表非常小的情況下)他可能就不會用索引和行級鎖而是采用表級鎖來全表掃描。
2. 死鎖
產(chǎn)生原因舉例:
會話A和B同時操作同一張表,A先給r1加了鎖,同時B給r2加了鎖,這時,A接著嘗試獲取r2的鎖,B嘗試獲取r1的鎖,于是就產(chǎn)生了死鎖。
避免死鎖的方法:
- 如果不同程序會并發(fā)存取多個表,盡量約定以相同的順序訪問表,可以大大降低發(fā)生死鎖的可能性;
- 在同一個事務(wù)中,盡可能做到一次鎖定所需要的所有資源,減少死鎖產(chǎn)生概率;
- 對于非常容易產(chǎn)生死鎖的業(yè)務(wù)部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產(chǎn)生的概率。
3. 共享鎖和排他鎖
(1)共享鎖
指共享讀鎖,即允許其他并發(fā)程序讀取數(shù)據(jù),但是如果想改數(shù)據(jù)必須等共享鎖釋放
使用方法:SELECT .... LOCK IN SHARE MODE
(2)排他鎖
指獨享寫鎖,即不允許其他線程修改或讀取數(shù)據(jù)。
SELECT ... FOR UPDATE
注意:共享鎖和排他鎖都是行級鎖
(3)意向鎖
意向鎖是表級鎖,InnoDB 中的兩個表鎖:
意向共享鎖(IS):表示事務(wù)準備給數(shù)據(jù)行加入共享鎖,也就是說一個數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖;
意向排他鎖(IX):類似上面,表示事務(wù)準備給數(shù)據(jù)行加入排他鎖,說明事務(wù)在一個數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖。
意向鎖是 InnoDB 自動加的,不需要用戶干預(yù)。
參考:
[1] 深入淺出MySQL
[2] http://www.hollischuang.com/archives/914
[3] https://blog.csdn.net/qq_35246620/article/details/69944175