目錄
- 鎖定義
- 鎖分類
- 讀鎖和寫鎖
- 表鎖和行鎖
- InnoDB共享鎖和排他鎖
- InnoDB意向鎖和排他鎖
- InnoDB行鎖
- InnoDB間隙鎖
- 概念
- InnoDB使用間隙鎖目的
- InnoDB行鎖實(shí)現(xiàn)方式
- 閑聊
- 【邁莫coding】
鎖定義
鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或線程并發(fā)訪問某一資源的機(jī)制。
在數(shù)據(jù)庫中,除了傳統(tǒng)的計(jì)算資源(如CPU, RAM, I/O等)的爭用以外,數(shù)據(jù)也是一種供需要用戶共享的資源。鎖沖突也是影響數(shù)據(jù)庫并發(fā)訪問性能的一個(gè)重要因素。
鎖分類
- 從性能上分為樂觀鎖(用版本對(duì)比來實(shí)現(xiàn))和悲觀鎖
- 從數(shù)據(jù)庫操作的類型分為讀鎖和寫鎖(都屬于悲觀鎖)
- 從對(duì)數(shù)據(jù)操作的粒度分:分為表鎖和行鎖
讀鎖和寫鎖
- 讀鎖(共享鎖):針對(duì)同一份數(shù)據(jù),多個(gè)讀操作可以同時(shí)進(jìn)行而不會(huì)互相影響,但是會(huì)阻塞寫操作
- 寫鎖(互斥鎖):當(dāng)前寫操作沒有完成前,它會(huì)阻斷其他寫鎖和讀鎖
表鎖和行鎖
表鎖
- 每次操作時(shí)會(huì)鎖住整張表。開銷小,加鎖快;不會(huì)發(fā)生死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高;并發(fā)度最低;
- 表鎖更適合于以查詢?yōu)橹?,并發(fā)用戶少,只有少量按索引條件更新數(shù)據(jù)的應(yīng)用,如Web應(yīng)用
行鎖
- 每次操作鎖住一行數(shù)據(jù)。開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低;并發(fā)度最高;
- 行級(jí)鎖只在存儲(chǔ)引擎層實(shí)現(xiàn),而mysql服務(wù)器沒有實(shí)現(xiàn)。
- 行級(jí)鎖更適合于有大量按索引條件并發(fā)更新少量不同數(shù)據(jù),同時(shí)又有并發(fā)查詢的應(yīng)用,如一些- 在線事務(wù)處理(OLTP)系統(tǒng)
InnoDB共享鎖和排他鎖
InnoDB實(shí)現(xiàn)了兩種類型的行鎖:
- 共享鎖(S): 允許一個(gè)事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖
- 排他鎖(X): 允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖
為了允許行鎖和表鎖共存,實(shí)現(xiàn)多粒度鎖機(jī)制,InnoDB還有兩種內(nèi)部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖:
- 意向共享鎖(IS):事務(wù)打算給數(shù)據(jù)行加行共享鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖
- 意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖
InnoDB意向鎖和排他鎖
意向鎖是 InnoDB 引擎自動(dòng)加的,不需要用戶干預(yù)
對(duì)于
UPDATEINSERTDELETE語句,InnoDB引擎會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X)對(duì)于普通
SELECT語句,InnoDB不會(huì)加任何鎖-
事務(wù)可以通過以下語句顯式地給結(jié)果集加共享鎖或排它鎖
- 共享鎖(S):
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。 其他 session 仍然可以查詢記錄,并也可以對(duì)該記錄加 share mode 的共享鎖。但是如果當(dāng)前事務(wù)需要對(duì)該記錄進(jìn)行更新操作,則很有可能造成死鎖。 - 排它鎖(X):
SELECT * FROM table_name WHERE ... FOR UPDATE。其他 session 可以查詢?cè)撚涗洠遣荒軐?duì)該記錄加共享鎖或排他鎖,而是等待獲得鎖
- 共享鎖(S):
InnoDB行鎖
- innoDB行鎖通過索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)的,這一點(diǎn) MySQL 與 Oracle 不同,后者是通過在數(shù)據(jù)塊中對(duì)相應(yīng)數(shù)據(jù)行加鎖來實(shí)現(xiàn)的。InnoDB 這種行鎖實(shí)現(xiàn)特點(diǎn)意味著:只有通過索引條件檢索數(shù)據(jù),InnoDB 才使用行級(jí)鎖,否則,InnoDB 將使用表鎖!
- 不論是使用主鍵索引、唯一索引或普通索引,InnoDB 都會(huì)使用行鎖來對(duì)數(shù)據(jù)加鎖。
- 只有執(zhí)行計(jì)劃真正使用了索引,才能使用行鎖:即便在條件中使用了索引字段,但是否使用索引來檢索數(shù)據(jù)是由 MySQL 通過判斷不同執(zhí)行計(jì)劃的代價(jià)來決定的,如果 MySQL 認(rèn)為全表掃描效率更高,比如對(duì)一些很小的表,它就不會(huì)使用索引,這種情況下 InnoDB 將使用表鎖,而不是行鎖。
- 由于 MySQL 的行鎖是針對(duì)索引加的鎖,不是針對(duì)記錄加的鎖,所以雖然多個(gè)session訪問不同行的記錄, 但是如果是使用相同的索引鍵, 是會(huì)出現(xiàn)鎖沖突的(后使用這些索引的session需要等待先使用索引的session釋放鎖后,才能獲取鎖)。 應(yīng)用設(shè)計(jì)的時(shí)候要注意這一點(diǎn)。
InnoDB間隙鎖
概念
當(dāng)我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請(qǐng)求共享或排他鎖時(shí),InnoDB會(huì)給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對(duì)于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會(huì)對(duì)這個(gè)“間隙”加鎖,這種鎖機(jī)制就是所謂的間隙鎖(Next-Key鎖)。
很顯然,在使用范圍條件檢索并鎖定記錄時(shí),InnoDB這種加鎖機(jī)制會(huì)阻塞符合條件范圍內(nèi)鍵值的并發(fā)插入,這往往會(huì)造成嚴(yán)重的鎖等待。因此,在實(shí)際應(yīng)用開發(fā)中,尤其是并發(fā)插入比較多的應(yīng)用,我們要盡量優(yōu)化業(yè)務(wù)邏輯,盡量使用相等條件來訪問更新數(shù)據(jù),避免使用范圍條件。
InnoDB使用間隙鎖的目的:
防止幻讀,以滿足相關(guān)隔離級(jí)別的要求;滿足恢復(fù)和復(fù)制的需要
-
MySQL 通過 BINLOG 錄入執(zhí)行成功的 INSERT 、 UPDATE 、 DELETE 等更新數(shù)據(jù)的 SQL 語句,并由此實(shí)現(xiàn) MySQL 數(shù)據(jù)庫的恢復(fù)和主從復(fù)制。MySQL 的恢復(fù)機(jī)制(復(fù)制其實(shí)就是在 Slave Mysql 不斷做基于 BINLOG 的恢復(fù))有以下特點(diǎn):
- 一是 MySQL 的恢復(fù)是 SQL 語句級(jí)的,也就是重新執(zhí)行 BINLOG 中的 SQL 語句。
- 二是 MySQL 的 Binlog 是按照事務(wù)提交的先后順序記錄的, 恢復(fù)也是按這個(gè)順序進(jìn)行的。
由此可見,MySQL 的恢復(fù)機(jī)制要求:在一個(gè)事務(wù)未提交前,其他并發(fā)事務(wù)不能插入滿足其鎖定條件的任何記錄,也就是不允許出現(xiàn)幻讀。
InnoDB加鎖方式
- 隱式鎖定:
InnoDB在事務(wù)執(zhí)行過程中,使用兩階段鎖協(xié)議:
隨時(shí)都可以執(zhí)行鎖定,InnoDB會(huì)根據(jù)隔離級(jí)別在需要的時(shí)候自動(dòng)加鎖;
鎖只有在執(zhí)行commit或者rollback的時(shí)候才會(huì)釋放,并且所有的鎖都是在同一時(shí)刻被釋放。
- 顯式鎖定 :
select ... lock in share mode //共享鎖
select ... for update //排他鎖
- select for update:
在執(zhí)行這個(gè) select 查詢語句的時(shí)候,會(huì)將對(duì)應(yīng)的索引訪問條目進(jìn)行上排他鎖(X 鎖),也就是說這個(gè)語句對(duì)應(yīng)的鎖就相當(dāng)于update帶來的效果。
- select *** for update 的使用場景
為了讓自己查到的數(shù)據(jù)確保是最新數(shù)據(jù),并且查到后的數(shù)據(jù)只允許自己來修改的時(shí)候,需要用到 for update 子句。
- select lock in share mode
in share mode 子句的作用就是將查找到的數(shù)據(jù)加上一個(gè) share 鎖,這個(gè)就是表示其他的事務(wù)只能對(duì)這些數(shù)據(jù)進(jìn)行簡單的select 操作,并不能夠進(jìn)行 DML 操作。
- select *** lock in share mode 使用場景
為了確保自己查到的數(shù)據(jù)沒有被其他的事務(wù)正在修改,也就是說確保查到的數(shù)據(jù)是最新的數(shù)據(jù),并且不允許其他人來修改數(shù)據(jù)。但是自己不一定能夠修改數(shù)據(jù),因?yàn)橛锌赡芷渌氖聞?wù)也對(duì)這些數(shù)據(jù) 使用了 in share mode 的方式上了 S 鎖。
- 性能影響
-
select for update語句,相當(dāng)于一個(gè)update語句。在業(yè)務(wù)繁忙的情況下,如果事務(wù)沒有及時(shí)的commit或者rollback 可能會(huì)造成其他事務(wù)長時(shí)間的等待,從而影響數(shù)據(jù)庫的并發(fā)使用效率。 -
select lock in share mode語句是一個(gè)給查找的數(shù)據(jù)上一個(gè)共享鎖(S 鎖)的功能,它允許其他的事務(wù)也對(duì)該數(shù)據(jù)上S鎖,但是不能夠允許對(duì)該數(shù)據(jù)進(jìn)行修改。如果不及時(shí)的commit或者rollback也可能會(huì)造成大量的事務(wù)等待。
閑聊
- 讀完文章,自己是不是和mysql鎖的cp率又提高了
- 我是邁莫,歡迎大家和我交流
文章也會(huì)持續(xù)更新,可以微信搜索「 邁莫coding 」第一時(shí)間閱讀。