您好,登錄后才能下訂單哦!
這篇文章主要介紹“mysql鎖的相關知識點介紹”,在日常操作中,相信很多人在mysql鎖的相關知識點介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”mysql鎖的相關知識點介紹”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
一、mysql的鎖類型
(1) 共享/排它鎖(Shared and Exclusive Locks)
共享鎖和排他鎖是InnoDB引擎實現的標準行級別鎖。
拿共享鎖是為了讓當前事務去讀一行數據。
拿排他鎖是為了讓當前事務去修改或刪除某一行數據。。
設置共享鎖:select * from user where id = 1 LOCK IN SHARE MODE;
設置排他鎖:select * from user where id = 1 FOR UPDATE;
(2) 意向鎖(Intention Locks)
意向鎖存在的意義在于,使得行鎖和表鎖能夠共存。
意向鎖是表級別的鎖,用來說明事務稍后會對表中的數據行加哪種類型的鎖(共享鎖或獨占鎖)。
當一個事務對表加了意向排他鎖時,另外一個事務在加鎖前就會通過該表的意向排他鎖知道前面已經有事務在對該表進行獨占操作,從而等待。
(3) 記錄鎖(Record Locks)
記錄鎖是索引記錄上的鎖,例如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;會阻止其他事務對c1=10的數據行進行插入、更新、刪除等操作。
記錄鎖總是鎖定索引記錄。如果一個表沒有定義索引,那么就會去鎖定隱式的“聚集索引”。
(4) 間隙鎖(Gap Locks)
間隙鎖是一個在索引記錄之間的間隙上的鎖。
一個間隙可能跨越單個索引值、多個索引值,甚至為空。
對于使用唯一索引 來搜索唯一行的語句,只加記錄鎖不加間隙鎖(這并不包括組合唯一索引)。
(5) 臨鍵鎖(Next-key Locks)
Next-Key Locks是行鎖與間隙鎖的組合。當InnoDB掃描索引記錄的時候,會首先對選中的索引記錄加上記錄鎖(Record Lock),然后再對索引記錄兩邊的間隙加上間隙鎖(Gap Lock)。
(6) 插入意向鎖(Insert Intention Locks)
插入意向鎖是在數據行插入之前通過插入操作設置的間隙鎖定類型。
如果多個事務插入到相同的索引間隙中,如果它們不在間隙中的相同位置插入,則無需等待其他事務。例如:在4和7的索引間隙之間兩個事務分別插入5和6,則兩個事務不會發沖突阻塞。
(7) 自增鎖(Auto-inc Locks)
自增鎖是事務插入到有自增列的表中而獲得的一種特殊的表級鎖。如果一個事務正在向表中插入值,那么任何其他事務都必須等待,保證第一個事務插入的行是連續的自增值。
二、鎖的實現方式
InnoDB行鎖是通過給索引加鎖來實現的,如果沒有索引,InnoDB會通過隱藏的聚簇索引來對記錄進行加鎖(全表掃描,也就是表鎖)。
但是,為了效率考量,MySQL做了優化,對于不滿足條件的記錄,會放鎖,最終持有的,是滿足條件的記錄上的鎖。但是不滿足條件的記錄上的加鎖/放鎖動作是不會省略的。所以在沒有索引時,不滿足條件的數據行會有加鎖又放鎖的耗時過程。
索引分為主鍵索引和非主鍵索引兩種。如果一條sql語句操作了主鍵索引,MySQL就會鎖定對應主鍵索引;如果一條語句操作了非主鍵索引,MySQL會先鎖定非主鍵索引,再鎖定對應的主鍵索引。
三、mysql鎖在4種事務隔離級別里的應用
事務的四種隔離級別有:
讀未提交(Read Uncommitted)
此時select語句不加任何鎖。此時并發最高,但會產生臟讀。
讀提交(Read Committed, RC)
普通select語句是快照讀
update語句、delete語句、顯示加鎖的select語句(select … in share mode 或者 select … for update) 等,除了在外鍵約束檢查和重復鍵檢查時會封鎖區間,其他情況都只使用記錄鎖;
可重復讀(Repeated Read, RR)
普通select語句也是快照讀
update語句、delete語句、顯示加鎖的select語句(select … in share mode 或者 select … for update)則要分情況:
在唯一索引上使用唯一的查詢條件,則使用記錄鎖。如: select * from user where id = 1;其中id建立了唯一索引。
在唯一索引上使用 范圍查詢條件,則使用間隙鎖與臨鍵鎖。如: select * from user where id >20;
串行化(Serializable)
此時所有select語句都會被隱式加鎖:select … in share mode.
四、快照讀、當前讀
要理解前面四種隔離級別的加鎖方式,對于MVCC、快照讀、當前讀 都是必須要理解的。
MVCC并發控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當前讀 (current read)。
快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。
當前讀,讀取的是記錄的最新版本,并且,當前讀返回的記錄,都會加上鎖,保證其他事務不會再并發修改這條記錄。
什么是多版本并發控制(MVCC:multi-version concurrency control )
1.MVCC定義:多版并發控制系統。可認為是行級鎖的一個變種,它能夠避免更多情況下的加鎖操作。
2.作用:避免一些加鎖操作,提升并發性能。
3.實現:通過在每行記錄的后面保存行的創建時間和過期時間或刪除時間(它們是隱藏的),這兩個時間實際都是系統的版本號。每開始一個新的事務,版本號都會自動增加。
4.具體原理
4.1) select:innoBD查詢時會檢查以下兩個條件:一個是數據行的版本號早于當前事務的版本號;另一個是行的刪除版本號,要么沒有,要么大于當前事務的版本號。
4.2)insert/delete:innoDB將當前的系統版本號作為新插入(刪除)的數據行的版本號。
4.3)update:先新插入一行數據,并將當前系統版本號作為行的版本號,同時將當前系統版本號作為原來行的刪除版本號。更新主鍵時,聚集索引和普通索引都會產生兩個版本;而更新非主鍵時,只要普通索引會產生兩個版本。
注意:MVCC只在read committed和repeatable read兩個隔離級別下工作。
[參考:《高性能mysql》]
快 照 讀 是 哪 些
一個正常的select…語句就是快照讀。
快照讀,使得在RR(repeatable read)級別下一個普通select...語句也能做到可重復讀。即前面MVCC里提到的利用可見版本來保證數據的一致性。
當 前 讀 是 哪 些
insert語句、update語句、delete語句、顯示加鎖的select語句(select… LOCK IN SHARE MODE、select… FOR UPDATE)是當前讀。
為什么insert、update、delete語句都屬于當前讀?
這是因為這些語句在執行時,都會執行一個讀取當前數據最新版本的過程。
當前讀的SQL語句,InnoDB是逐條與MySQL Server交互的。即先對一條滿足條件的記錄加鎖后,再返回給MySQL Server,當MySQL Server做完DML操作后,再對下一條數據加鎖并處理。
五、查看行級鎖爭用情況
執行SQL:mysql> show status like 'InnoDB_row_lock%';
mysql> show status like 'InnoDB_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| InnoDB_row_lock_current_waits | 0 |
| InnoDB_row_lock_time | 0 |
| InnoDB_row_lock_time_avg | 0 |
| InnoDB_row_lock_time_max | 0 |
| InnoDB_row_lock_waits | 0 |
+-------------------------------+-------+
如果發現鎖爭用比較嚴重,還可以通過設置InnoDB Monitors 來進一步觀察發生鎖沖突的表、數據行等,并分析鎖爭用的原因。如:
設置監視器:mysql> create table InnoDB_monitor(a INT) engine=InnoDB;
查看:mysql> show engine InnoDB status;
停止查看:mysql> drop table InnoDB_monitor;
具體參考:InnoDB Monitor
六、死鎖
什么是死鎖:你等我釋放鎖,我等你釋放鎖就會形成死鎖。
如何發現死鎖:在InnoDB的事務管理和鎖定機制中,有專門檢測死鎖的機制,會在系統中產生死鎖之后的很短時間內就檢測到該死鎖的存在
解決辦法:回滾較小的那個事務
在REPEATABLE-READ隔離級別下,如果兩個線程同時對相同條件記錄用SELECT…FOR UPDATE加排他鎖,在沒有符合該條件記錄情況下,兩個線程都會加鎖成功。程序發現記錄尚不存在,就試圖插入一條新記錄,如果兩個線程都這么做,就會出現死鎖。這種情況下,將隔離級別改成READ COMMITTED,就可避免問題。
如何判斷事務大小:事務各自插入、更新或者刪除的數據量
注意:
當產生死鎖的場景中涉及到不止InnoDB存儲引擎的時候,InnoDB是沒辦法檢測到該死鎖的,這時候就只能通過鎖定超時限制參數InnoDB_lock_wait_timeout來解決。
七、優化行級鎖定
(1)要想合理利用InnoDB的行級鎖定,做到揚長避短,我們必須做好以下工作:
a)盡可能讓所有的數據檢索都通過索引來完成,從而避免InnoDB因為無法通過索引鍵加鎖而升級為表級鎖定;
b)合理設計索引,讓InnoDB在索引鍵上面加鎖的時候盡可能準確,盡可能的縮小鎖定范圍,避免造成不必要的鎖定而影響其他Query的執行;
c)盡可能減少基于范圍的數據檢索過濾條件,避免因為間隙鎖帶來的負面影響而鎖定了不該鎖定的記錄;
d)盡量控制事務的大小,減少鎖定的資源量和鎖定時間長度;
e)在業務環境允許的情況下,盡量使用較低級別的事務隔離,以減少MySQL因為實現事務隔離級別所帶來的附加成本。
(2)由于InnoDB的行級鎖定和事務性,所以肯定會產生死鎖,下面是一些比較常用的減少死鎖產生概率的小建議:
a)類似業務模塊中,盡可能按照相同的訪問順序來訪問,防止產生死鎖;
b)在同一個事務中,盡可能做到一次鎖定所需要的所有資源,減少死鎖產生概率;
c)對于非常容易產生死鎖的業務部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率。
查看SQL語句的鎖信息
查看sql句的鎖信息前,需要做如下幾件事:
查看事務的隔離級別:
通過show global variables like “tx_isolation”; 命令查看。
可通過執行set session transaction isolation level repeatable read;更改成我們想要隔離級別,隔離級別取值如下:
read uncommitted、read committed、repeatable read、serializable
保證事務為手動提交:
通過show global variables like “autocommit”;查看。
如果為ON,則通過執行set session autocommit=0;改為手動提交。
保證間隙鎖開啟:
通過show global variables like “innodb_locks%”;查看
OFF時表示開啟。默認是OFF
到此,關于“mysql鎖的相關知識點介紹”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。