当前位置:网站首页> MySQL進階系列:鎖-InnoDB中鎖的情况
MySQL進階系列:鎖-InnoDB中鎖的情况
2022-06-24 16:01:00 【紀先生】
持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第6天,點擊查看活動詳情
MySQL鎖-InnoDB中鎖的情况
mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 5.7.21 |
+-----------+
1 row in set (0.01 sec)
一,鎖的基本介紹
相對其他數據庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,MyISAM和MEMORY存儲引擎采用的是錶級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖(row-level locking),也支持錶級鎖,但默認情况下是采用行級鎖。
錶級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。
行級鎖類型:
Record Lock(記錄鎖):當個記錄的鎖(鎖住單條記錄)
記錄鎖只會鎖住索引的記錄,如果InnoDB存儲錶在建立的時候沒有任何索引,那麼這個鎖會使用隱式的主鍵來進行鎖定,如下圖
Gap Lock(間隙鎖):鎖定一個範圍,不包括記錄本身(只鎖數據前面的GAP)
如下圖為的鎖就是GAP鎖,就是不允許其他事務在索引列8之前的間隙插入新的記錄,也就是(3 , 8)這個區間。gap鎖 的作用僅僅是為了防止插入幻影記錄的而已
Next-Key Lock(臨鍵鎖):同時鎖住記錄和記錄前面的GAP,也就是Next-Key Lock = Record Lock + Gap Lock。
二,鎖的分類
共享鎖 Share Locks (簡稱S鎖,屬於行鎖)
排它鎖 Exclusive Locks (簡稱X鎖,屬於行鎖)
意向共享鎖 Intention Share Locks (簡稱IS鎖,屬於錶鎖)
意向排它鎖 Intention Exclusive Locks (簡稱IX鎖,屬於錶鎖)
自增鎖 AUTO-INC Locks(屬於錶鎖)
下面具體介紹下每種類型的鎖,我們先建一張innodb的錶,sql如下
create table tab_with_index(id int,name varchar(10)) engine=innodb;
alter table tab_with_index add index id(id);
insert into tab_with_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
共享鎖
共享鎖就是多個事務對於同一個數據可以共享一把鎖,都能訪問數據庫,但是只能讀不能修改;
事務A:
select * from tab_with_index lock in share mode;
事務B:
select * from tab_with_index where id =1; // 可以查詢數據
update tab_with_index set name = 'aa' where id = 1 ;
注意:這裏的修改語句會堵塞住,直到事務A提交之後才能操作成功。
排它鎖
排它鎖不能與其他鎖並存,如一個事務獲取了一個數據行的排它鎖,其他事務就不能在獲取該行的鎖,只有當前獲取排它鎖的事務可以對數據進行修改。(delete,update,create默認是排它鎖)
事務A:
select * from tab_with_index where id =1 for update;
事務B:
select * from tab_with_index where id =1; //可以獲取結果
select * from tab_with_index where id =1 for update; // 堵塞
select * from tab_with_index where id = 1 lock for share mode; // 堵塞
注意:事務B兩個sql都會堵塞住,也就是獲取不到共享鎖也獲取不到排它鎖,直到事務A提交之後才能操作成功。
意向共享鎖和意向排它鎖
意向共享鎖:錶示事務准備給數據行加入共享鎖,也就是說一個數據行在加共享鎖之前必須先獲取該錶的IS鎖。
意向排它鎖:錶示事務准備給數據行加入排它鎖,也就是說一個數據行加排它鎖之前必須先獲取該錶的IX鎖。
IS鎖和IX鎖是錶級鎖,他們的提出僅僅為了在之後加錶級別的S鎖和X鎖時可以快速判斷錶中的記錄是否被上鎖,以避免用遍曆的方式來查看錶中有沒有上鎖的記錄,也就是說其實IS鎖和IX鎖是兼容的,IX鎖和IX鎖是兼容的。 《MySQL是怎樣運行的》
自增鎖
針對自增列自增長的一個特殊的錶級別鎖。
show variables like 'innodb_autoinc_lock_mode';
-- 默認值1,代錶連續,事務未提交則ID永久丟失
三,InnoDB鎖
1、事務及其ACID屬性
事務是由一組SQL語句組成的邏輯處理單元,事務具有4屬性,通常稱為事務的ACID屬性。
原子性(Actomicity):事務是一個原子操作單元,其對數據的修改,要麼全都執行,要麼全都不執行。 一致性(Consistent):在事務開始和完成時,數據都必須保持一致狀態。 隔離性(Isolation):數據庫系統提供一定的隔離機制,保證事務在不受外部並發操作影響的“獨立”環境執行。 持久性(Durable):事務完成之後,它對於數據的修改是永久性的,即使出現系統故障也能够保持。
2、並發事務帶來的問題
相對於串行處理來說,並發事務處理能大大增加數據庫資源的利用率,提高數據庫系統的事務吞吐量,從而可以支持更多用戶的並發操作,但與此同時,會帶來一下問題:
髒讀: 一個事務正在對一條記錄做修改,在這個事務並提交前,這條記錄的數據就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”的數據,並據此做進一步的處理,就會產生未提交的數據依賴關系。這種現象被形象地叫做“髒讀”
不可重複讀:一個事務在讀取某些數據已經發生了改變、或某些記錄已經被删除了!這種現象叫做“不可重複讀”。
幻讀: 一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱為“幻讀”
上述出現的問題都是數據庫讀一致性的問題,可以通過事務的隔離機制來進行保證。
數據庫的事務隔離越嚴格,並發副作用就越小,但付出的代價也就越大,因為事務隔離本質上就是使事務在一定程度上串行化,需要根據具體的業務需求來决定使用哪種隔離級別
| 髒讀 | 不可重複讀 | 幻讀 | |
|---|---|---|---|
| read uncommitted | √ | √ | √ |
| read committed | √ | √ | |
| repeatable read | √ | ||
| serializable |
可以通過檢查InnoDB_row_lock狀態變量來分析系統上的行鎖的爭奪情况:
mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 18702 |
| Innodb_row_lock_time_avg | 18702 |
| Innodb_row_lock_time_max | 18702 |
| Innodb_row_lock_waits | 1 |
+-------------------------------+-------+
--如果發現鎖爭用比較嚴重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比較高
3、InnoDB的行鎖模式及加鎖方法
共享鎖(S) :又稱讀鎖(lock in share mode)。允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。 排他鎖(X) :又稱寫鎖(for update)。允許獲取排他鎖的事務更新數據,阻止其他事務取得相同的數據集共享讀鎖和排他寫鎖。若事務T對數據對象A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。
mysql InnoDB引擎默認的修改數據語句:update,delete,insert都會自動給涉及到的數據加上排他鎖,select語句默認不會加任何鎖類型,如果加排他鎖可以使用select …for update語句,加共享鎖可以使用select … lock in share mode語句。所以加過排他鎖的數據行在其他事務中是不能修改數據的,也不能通過for update和lock in share mode鎖的方式查詢數據,但可以直接通過select …from…查詢數據,因為普通查詢沒有任何鎖機制。
4、InnoDB行鎖實現方式
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,這一點MySQL與Oracle不同,後者是通過在數據塊中對相應數據行加鎖來實現的。InnoDB這種行鎖實現特點意味著:只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用錶鎖!
1、在不通過索引條件查詢的時候,innodb使用的是錶鎖而不是行鎖
create table tab_no_index(id int,name varchar(10)) engine=innodb;
insert into tab_no_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
| session1 | session2 |
|---|---|
| set autocommit=0 select * from tab_no_index where id = 1; | set autocommit=0 select * from tab_no_index where id =2 |
| select * from tab_no_index where id = 1 for update | |
| select * from tab_no_index where id = 2 for update; |
session1只給一行加了排他鎖,但是session2在請求其他行的排他鎖的時候,會出現鎖等待。原因是在沒有索引的情况下,innodb只能使用錶鎖。
2、創建帶索引的錶進行條件查詢,innodb使用的是行鎖
create table tab_with_index(id int,name varchar(10)) engine=innodb;
alter table tab_with_index add index id(id);
insert into tab_with_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
| session1 | session2 |
|---|---|
| set autocommit=0 select * from tab_with_indexwhere id = 1; | set autocommit=0 select * from tab_with_indexwhere id =2 |
| select * from tab_with_indexwhere id = 1 for update | |
| select * from tab_with_indexwhere id = 2 for update; |
3、由於mysql的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是依然無法訪問到具體的數據(這裏是錶鎖)
alter table tab_with_index drop index id;
insert into tab_with_index values(1,'4');
| session1 | session2 |
|---|---|
| set autocommit=0 | set autocommit=0 |
| select * from tab_with_index where id = 1 and name='1' for update | |
| select * from tab_with_index where id = 1 and name='4' for update 雖然session2訪問的是和session1不同的記錄,但是鎖的是具體錶,所以需要等待鎖 |
總結
對於InnoDB錶,本文主要討論了以下幾項內容: (1)InnoDB的行鎖是基於索引實現的,如果不通過索引訪問數據,InnoDB會使用錶鎖。 (2)在不同的隔離級別下,InnoDB的鎖機制和一致性讀策略不同。
在了解InnoDB鎖特性後,用戶可以通過設計和SQL調整等措施减少鎖沖突和死鎖,包括:
- 盡量使用較低的隔離級別; 精心設計索引,並盡量使用索引訪問數據,使加鎖更精確,從而减少鎖沖突的機會;
- 選擇合理的事務大小,小事務發生鎖沖突的幾率也更小;
- 給記錄集顯式加鎖時,最好一次性請求足够級別的鎖。比如要修改數據的話,最好直接申請排他鎖,而不是先申請共享鎖,修改時再請求排他鎖,這樣容易產生死鎖;
- 不同的程序訪問一組錶時,應盡量約定以相同的順序訪問各錶,對一個錶而言,盡可能以固定的順序存取錶中的行。這樣可以大大减少死鎖的機會;
- 盡量用相等條件訪問數據,這樣可以避免間隙鎖對並發插入的影響; 不要申請超過實際需要的鎖級別;除非必須,查詢時不要顯示加鎖;
- 對於一些特定的事務,可以使用錶鎖來提高處理速度或减少死鎖的可能。
我是紀先生,用輸出倒逼輸入而持續學習,持續分享技術系列文章,以及全網值得收藏好文,歡迎關注公眾號,做一個持續成長的技術人。
mysql進階系列曆史文章
(也可以在掘金專欄中看其他相關文章)
3. MySQL進階系列:mysql中MyISAM和InnoDB有什麼區別;
4. MySQL進階系列:mysql中錶設計如何更好的選擇數據類型;
5. MySQL進階系列:數據庫設計中的範式究竟該如何使用;
6. MySQL進階系列:一文詳解explain各字段含義;
7. MySQL進階系列:為什麼mysql使用B+作為索引的數據結構;
边栏推荐
- 个人常用的高效工具
- great! The novel website project is completely open source
- 2021-04-18: given a two-dimensional array matrix, the value in it is either 1 or 0,
- 【应用推荐】最近大火的Apifox & Apipost 上手体验与选型建议
- 2021-04-28: force buckle 546, remove the box. Give some boxes of different colors
- Introduction to new features of ECMAScript 2019 (ES10)
- Istio practical skill: hide the automatically added server header
- A new weapon to break the memory wall has become a "hot search" in the industry! Persistent memory enables workers to play with massive data + high-dimensional models
- MySQL Innodb和Myisam
- ThinkPHP 漏洞利用工具
猜你喜欢

【面试高频题】难度 3/5,可直接构造的序列 DP 题

Logging is not as simple as you think

Mongodb introductory practical tutorial: learning summary directory
![[cloud native | kubernetes chapter] Introduction to kubernetes Foundation (III)](/img/21/503ed54a2fa14fbfd67f75a55ec286.png)
[cloud native | kubernetes chapter] Introduction to kubernetes Foundation (III)

The equipment is connected to the easycvr platform through the national standard gb28181. How to solve the problem of disconnection?
![clang: warning: argument unused during compilation: ‘-no-pie‘ [-Wunused-command-line-argument]](/img/f0/42f394dbc989d381387c7b953d2a39.jpg)
clang: warning: argument unused during compilation: ‘-no-pie‘ [-Wunused-command-line-argument]

存在安全隐患 部分冒险家混动版将召回

Build go command line program tool chain

Understanding openstack network

CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021
随机推荐
April 30, 2021: there are residential areas on a straight line, and the post office can only be built on residential areas. Given an ordered positive array arr
[application recommendation] the hands-on experience and model selection suggestions of apifox & apipost in the recent fire
企业安全攻击面分析工具
Build go command line program tool chain
Remote connection raspberry pie in VNC Viewer Mode
Linux record -4.22 MySQL 5.37 installation (supplementary)
2021-05-01: given an ordered array arr, it represents the points located on the X axis. Given a positive number k
山金期货安全么?期货开户都是哪些流程?期货手续费怎么降低?
2021-05-03: given a non negative integer num, how to avoid circular statements,
2021-04-24: handwriting Code: topology sorting.
The first in China! Tencent cloud key management system passes password application verification test
The equipment is connected to the easycvr platform through the national standard gb28181. How to solve the problem of disconnection?
一文理解OpenStack网络
Reference to junit5 test framework in gradle
PyTorch中的转置卷积详解
My network relationship with "apifox"
我与“Apifox”的网络情缘
【Prometheus】5. Alertmanager alarm (incomplete)
great! The novel website project is completely open source
sql 多表更新数据非常慢