您好,登錄后才能下訂單哦!
這篇文章主要介紹了MySQL鎖機制的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
鎖在MySQL中是非常重要的一部分,鎖對MySQL的數據訪問并發(fā)有著舉足輕重的影響。鎖涉及到的知識篇幅也很多,所以要啃完并消化到自己的肚子里,是需要靜下心好好反反復復幾遍地細細品味。本文是對鎖的一個大概的整理,一些相關深入的細節(jié),還是需要找到相關書籍來繼續(xù)夯實。
鎖的認識
1.1 鎖的解釋
計算機協調多個進程或線程并發(fā)訪問某一資源的機制。
1.2 鎖的重要性
在數據庫中,除傳統(tǒng)計算資源(CPU、RAM、I\O等)的爭搶,數據也是一種供多用戶共享的資源。 如何保證數據并發(fā)訪問的一致性,有效性,是所有數據庫必須要解決的問題。 鎖沖突也是影響數據庫并發(fā)訪問性能的一個重要因素,因此鎖對數據庫尤其重要。
1.3 鎖的缺點
加鎖是消耗資源的,鎖的各種操作,包括獲得鎖、檢測鎖是否已解除、釋放鎖等 ,都會增加系統(tǒng)的開銷。
1.4 簡單的例子
現如今網購已經特別普遍了,比如淘寶雙十一活動,當天的人流量是千萬及億級別的,但商家的庫存是有限的。 系統(tǒng)為了保證商家的商品庫存不發(fā)生超賣現象,會對商品的庫存進行鎖控制。當有用戶正在下單某款商品最后一件時, 系統(tǒng)會立馬對該件商品進行鎖定,防止其他用戶也重復下單,直到支付動作完成才會釋放(支付成功則立即減庫存售罄,支付失敗則立即釋放)。
鎖的類型
2.1 表鎖
種類
讀鎖(read lock),也叫共享鎖(shared lock) 針對同一份數據,多個讀操作可以同時進行而不會互相影響(select)
寫鎖(write lock),也叫排他鎖(exclusive lock) 當前操作沒完成之前,會阻塞其它讀和寫操作(update、insert、delete)
存儲引擎默認鎖
MyISAM
特點
1. 對整張表加鎖 2. 開銷小 3. 加鎖快 4. 無死鎖 5. 鎖粒度大,發(fā)生鎖沖突概率大,并發(fā)性低
1. 讀鎖會阻塞寫操作,不會阻塞讀操作 2. 寫鎖會阻塞讀和寫操作
MyISAM的讀寫鎖調度是寫優(yōu)先,這也是MyISAM不適合做寫為主表的引擎,因為寫鎖以后,其它線程不能做任何操作,大量的更新使查詢很難得到鎖,從而造成永遠阻塞。
2.2 行鎖
種類
讀鎖(read lock),也叫共享鎖(shared lock) 允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖
寫鎖(write lock),也叫排他鎖(exclusive lock) 允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的共享鎖和排他鎖
意向共享鎖(IS) 一個事務給一個數據行加共享鎖時,必須先獲得表的IS鎖
意向排它鎖(IX) 一個事務給一個數據行加排他鎖時,必須先獲得該表的IX鎖
InnoDB
1. 對一行數據加鎖 2. 開銷大 3. 加鎖慢 4. 會出現死鎖 5. 鎖粒度小,發(fā)生鎖沖突概率最低,并發(fā)性高
1. 更新丟失 解決:讓事務變成串行操作,而不是并發(fā)的操作,即對每個事務開始---對讀取記錄加排他鎖 2. 臟讀 解決:隔離級別為Read uncommitted 3. 不可重讀 解決:使用Next-Key Lock算法來避免 4. 幻讀 解決:間隙鎖(Gap Lock)
開銷、加鎖時間和鎖粒度介于表鎖和行鎖之間,會出現死鎖,并發(fā)處理能力一般(此鎖不做多介紹)
如何上鎖?
3.1 表鎖
select //上讀鎖
insert、update、delete //上寫鎖
lock table tableName read;//讀鎖 lock table tableName write;//寫鎖
unlock tables;//所有鎖表
session01 | session02 |
---|---|
lock table teacher read;//上讀鎖 | |
select * from teacher; //可以正常讀取 | select * from teacher;//可以正常讀取 |
update teacher set name = 3 where id =2;//報錯因被上讀鎖不能寫操作 | update teacher set name = 3 where id =2;//被阻塞 |
unlock tables;//解鎖 | |
update teacher set name = 3 where id =2;//更新操作成功 |
session01 | session02 |
---|---|
lock table teacher write;//上寫鎖 | |
select * from teacher; //可以正常讀取 | select * from teacher;//被阻塞 |
update teacher set name = 3 where id =2;//可以正常更新操作 | update teacher set name = 4 where id =2;//被阻塞 |
unlock tables;//解鎖 | |
select * from teacher;//讀取成功 | |
update teacher set name = 4 where id =2;//更新操作成功 |
3.2 行鎖
隱式上鎖(默認,自動加鎖自動釋放)
select //不會上鎖
insert、update、delete //上寫鎖
select * from tableName lock in share mode;//讀鎖 select * from tableName for update;//寫鎖
1. 提交事務(commit) 2. 回滾事務(rollback) 3. kill 阻塞進程
session01 | session02 |
---|---|
begin; | |
select * from teacher where id = 2 lock in share mode;//上讀鎖 | |
select * from teacher where id = 2;//可以正常讀取 | |
update teacher set name = 3 where id =2;// 可以更新操作 | update teacher set name = 5 where id =2;//被阻塞 |
commit; | |
update teacher set name = 5 where id =2;//更新操作成功 |
session01 | session02 |
---|---|
begin; | |
select * from teacher where id = 2 for update;//上寫鎖 | |
select * from teacher where id = 2;//可以正常讀取 | |
update teacher set name = 3 where id =2;// 可以更新操作 | update teacher set name = 5 where id =2;//被阻塞 |
rollback; | |
update teacher set name = 5 where id =2;//更新操作成功 |
為什么上了寫鎖,別的事務還可以讀操作? 因為InnoDB有MVCC機制(多版本并發(fā)控制),可以使用快照讀,而不會被阻塞。
行鎖的實現算法
4.1 Record Lock鎖
單個行記錄上的鎖 Record Lock總是會去鎖住索引記錄,如果InnoDB存儲引擎表建立的時候沒有設置任何一個索引,這時InnoDB存儲引擎會使用隱式的主鍵來進行鎖定
4.2 Gap Lock鎖
當我們用范圍條件而不是相等條件檢索數據,并請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引加鎖,對于鍵值在條件范圍內但并不存在的記錄。 優(yōu)點:解決了事務并發(fā)的幻讀問題 不足:因為query執(zhí)行過程中通過范圍查找的話,他會鎖定爭個范圍內所有的索引鍵值,即使這個鍵值并不存在。 間隙鎖有一個致命的弱點,就是當鎖定一個范圍鍵值之后,即使某些不存在的鍵值也會被無辜的鎖定,而造成鎖定的時候無法插入鎖定鍵值范圍內任何數據。在某些場景下這可能會對性能造成很大的危害。
4.3 Next-key Lock鎖
同時鎖住數據+間隙鎖 在Repeatable Read隔離級別下,Next-key Lock 算法是默認的行記錄鎖定算法。
4.4 行鎖的注意點
1. 只有通過索引條件檢索數據時,InnoDB才會使用行級鎖,否則會使用表級鎖(索引失效,行鎖變表鎖) 2. 即使是訪問不同行的記錄,如果使用的是相同的索引鍵,會發(fā)生鎖沖突 3. 如果數據表建有多個索引時,可以通過不同的索引鎖定不同的行
如何排查鎖?
5.1 表鎖
show open tables;
show status like 'table%';
1. table_locks_waited 出現表級鎖定爭用而發(fā)生等待的次數(不能立即獲取鎖的次數,每等待一次值加1),此值高說明存在著較嚴重的表級鎖爭用情況 2. table_locks_immediate 產生表級鎖定次數,不是可以立即獲取鎖的查詢次數,每立即獲取鎖加1
5.2 行鎖
行鎖分析
show status like 'innodb_row_lock%';
1. innodb_row_lock_current_waits //當前正在等待鎖定的數量 2. innodb_row_lock_time //從系統(tǒng)啟動到現在鎖定總時間長度 3. innodb_row_lock_time_avg //每次等待所花平均時間 4. innodb_row_lock_time_max //從系統(tǒng)啟動到現在等待最長的一次所花時間 5. innodb_row_lock_waits //系統(tǒng)啟動后到現在總共等待的次數
1. innodb_lock_waits表 2. innodb_locks表 3. innodb_trx表
1. 盡可能讓所有數據檢索都通過索引來完成,避免無索引行鎖升級為表鎖 2. 合理設計索引,盡量縮小鎖的范圍 3. 盡可能較少檢索條件,避免間隙鎖 4. 盡量控制事務大小,減少鎖定資源量和時間長度 5. 盡可能低級別事務隔離
死鎖
6.1 解釋
指兩個或者多個事務在同一資源上相互占用,并請求鎖定對方占用的資源,從而導致惡性循環(huán)的現象
6.2 產生的條件
1. 互斥條件:一個資源每次只能被一個進程使用 2. 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放 3. 不剝奪條件:進程已獲得的資源,在沒有使用完之前,不能強行剝奪 4. 循環(huán)等待條件:多個進程之間形成的一種互相循環(huán)等待的資源的關系
6.1 解決
1. 查看死鎖:show engine innodb status \G 2. 自動檢測機制,超時自動回滾代價較小的事務(innodb_lock_wait_timeout 默認50s) 3. 人為解決,kill阻塞進程(show processlist) 4. wait for graph 等待圖(主動檢測)
6.1 如何避免
1. 加鎖順序一致,盡可能一次性鎖定所需的數據行 2. 盡量基于primary(主鍵)或unique key更新數據 3. 單次操作數據量不宜過多,涉及表盡量少 4. 減少表上索引,減少鎖定資源 5. 盡量使用較低的隔離級別 6. 盡量使用相同條件訪問數據,這樣可以避免間隙鎖對并發(fā)的插入影響 7. 精心設計索引,盡量使用索引訪問數據 8. 借助相關工具:pt-deadlock-logger
樂觀鎖與悲觀鎖
7.1 悲觀鎖
假定會發(fā)生并發(fā)沖突,屏蔽一切可能違反數據完整性的操作
表鎖、行鎖等
數據庫本身
并發(fā)量大
7.2 樂觀鎖
假設不會發(fā)生并發(fā)沖突,只在提交操作時檢查是否違反數據完整性
提交更新時檢查版本號或者時間戳是否符合
業(yè)務代碼
并發(fā)量小
感謝你能夠認真閱讀完這篇文章,希望小編分享的“MySQL鎖機制的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業(yè)資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。