MySql-鎖
一、事務
事務與ACID屬性
原子性(Atomicity)、一致性(Consistent)、隔離性(Isolation)、永續性(Durable)
併發事務處理帶來的問題
更新丟失:兩個事務同時操作相同的資料,後提交的事務會覆蓋先提交的事務處理結果,通過樂觀鎖就可以解決
髒讀:事務A讀取到了事務B已經修改但尚未提交的資料,如果B事務回滾,A讀取的資料無效,不符合一致性。
不可重讀:事務A讀取了事務B已經提交的修改資料,不符合隔離性。
幻讀:事務A讀取到了事務B提交的新增資料,不符合隔離性
事務隔離級別
1.檢視資料庫事務隔離級別:show variables like 'tx_isolation';
2.設定事務隔離級別:set tx_isolation='REPEATABLE-READ';
預設是可重複度讀級別(RepeatableRead),客序列化(Serializable)效能很低
二、鎖分類
鎖定義
鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。分為表鎖(MyISAM)和行鎖 (Innodb)
行鎖(特性)
開銷大、加鎖慢、會出現死鎖、鎖定粒度小、併發高、偏向InnoDB儲存引擎(支援事務)、發生鎖衝突的概率最低
在InnoDB事務中,行鎖是在需要時才加上的,但不是不需要了就立刻釋放,而要等事務結束時才釋放。
如果你的事務中需要鎖多個行,要把最可能造成鎖衝突、最可能影響併發度的鎖儘量往後放。
表鎖(特性):
開銷小、加鎖快、鎖定粒度大、併發度最低、偏向MyISAM儲存引擎(不支援事務)、發生鎖衝突的概率最高
表鎖(操作命令):
加表鎖: lock table 表名稱 read(write),表名稱2 read(write);
查看錶鎖:show open tables;
刪除表鎖:unlock tables;
總結:
MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行增刪改操作前,會自動給設計的表加寫鎖。
讀鎖會阻塞寫,但不會阻塞讀。
寫鎖則會吧讀和寫都阻塞。
三、鎖
InnoDB行鎖可細分為記錄鎖(Record Lock)、間隙鎖(Gap Lock)、臨鍵鎖(Next_Key_Lock),是基於索引實現的,其本質是三種加鎖演算法。(若不宣告,預設採用RR隔離級別)
這三種並不是鎖,而是鎖的演算法。它們的共同特點是互斥的。間隙鎖和臨鍵鎖只有在RR級別中才能生效。
共享鎖
又名讀鎖、S鎖,屬於悲觀鎖。當事務A在執行讀鎖未提交時,事務B可以進行讀鎖,不可以進行寫鎖。select不加鎖
使用場景:讀取資料後,其他事務不能修改,但是自己也不一定能修改,因為其他事務也可以使用" select ....lock in share mode "繼續加讀鎖。
排他鎖
又名寫鎖、X鎖,屬於悲觀鎖。當事務A在執行寫鎖未提交時,事務B不可以進行寫鎖和讀鎖。update、insert、delete自帶寫鎖。
使用場景:讀取資料後,其他事務即不能寫,也不能加讀鎖,那麼就導致只有自己可以修改資料。
select ... for update 查詢加寫鎖
delete:刪除一條資料時,先對記錄加X鎖,再執行刪除操作。
insert:插入一條記錄時,會先加隱式鎖來保護這條新插入的記錄再本事務提交前不被別的事務訪問到。
隱式鎖:一個事務插入一條記錄後,還未提交,這條記錄會儲存本次事務id,而其他事務如果想來對這個記錄加鎖時會發現事務id不對應,這時會產生寫鎖,所以相當於再插一條記錄時,隱式的給這條記錄加一把隱式的寫鎖。
update:如果被更新的列,修改前後沒有導致儲存空間變化,那麼會先給記錄加寫鎖,再直接對記錄進行修改。
如果被更新的列,修改前後導致儲存空間變化,那麼會先給記錄加寫鎖,然後將記錄刪除掉,再insert一條新記錄。
意向共享鎖
又名IS。通知資料庫接下來需要施加什麼鎖並對錶加鎖。如果需要對記錄A加共享鎖,那麼此時innodb會先找到這張表,對該表加意向共享鎖之後,再對記錄A新增共享鎖(都是系統自動新增和自動釋放的,整個過程無需人工干預
)。
意向排他鎖
又名IX。通知資料庫接下來需要施加什麼鎖並對錶加鎖。如果需要對記錄A加排他鎖,那麼此時innodb會先找到這張表,對該表加意向排他鎖之後,再對記錄A新增排他鎖(都是系統自動新增和自動釋放的,整個過程無需人工干預
)。
自增鎖
已執行一條插入自增資料id=10,發生了回滾。這時再次執行新增資料將從id=11開始,雖然id=10並不存在。
如果存在自增欄位,MySQL會維護一個自增鎖,和自增鎖相關的一個引數(5.1.22版本之後加入)
記錄鎖(Record Lock)
鎖精確加在某一行上。一般要通過主鍵或唯一索引加鎖。
select * from fruit where id = 50 for update; # 記錄鎖
id 為 50的記錄行會被鎖住
需要注意的是:id
列必須為唯一索引列
或主鍵列
,否則上述語句加的鎖就會變成臨鍵鎖
。
同時查詢語句必須為精準匹配
(=
),不能為>
、<
、like
等,否則也會退化成臨鍵鎖。
間隙鎖(Gap Locks)
間隙鎖基於非唯一索引
,它鎖定一段範圍內的索引記錄
。間隙鎖基於下面將會提到的Next-Key Locking
演算法,請務必牢記:使用間隙鎖鎖住的是一個區間,而不僅僅是這個區間中的每一條資料
SELECT
*
FROM
table
WHERE
id BETWEN 1
AND
10
FOR
UPDATE
;
即所有在(1,10)
區間內的記錄行都會被鎖住,所有id 為 2、3、4、5、6、7、8、9 的資料行的插入會被阻塞,但是 1 和 10 兩條記錄行並不會被鎖住。
除了手動加鎖外,在執行完某些 SQL 後,InnoDB 也會自動加間隙鎖,這個我們在下面會提到。
臨鍵鎖(Next-Key-Locks)
記錄鎖與間隙鎖組合起來用就叫做Next-Key Lock,就是將鍵及其兩邊的的間隙加鎖(Next-Key 可以理解為一種特殊的間隙鎖,也可以理解為一種特殊的演算法。通過臨建鎖可以解決幻讀
的問題)。
每個資料行上的非唯一索引列
上都會存在一把臨鍵鎖,當某個事務持有該資料行的臨鍵鎖時,會鎖住一段左開右閉區間的資料。
需要強調的一點是,InnoDB
中行級鎖
是基於索引實現的,臨鍵鎖只與非唯一索引列
有關,在唯一索引列
(包括主鍵列
)上不存在臨鍵鎖。