目錄
鎖的類型
mysql鎖一般有兩種類型,一種是latch,該鎖是mysql程序的線程鎖,快速釋放,相當於java裏面的syn.還有一種是lock,這種鎖是針對innodb事務的,分爲行鎖和表鎖.
行鎖
行鎖分爲S鎖和X鎖,S鎖是共享鎖,X鎖是排他鎖.如下圖
S | 共享 | 事務讀某行 |
X | 排他 | 事務修改某行 |
它們的兼容性,S鎖之間兼容,只要有X鎖就不兼容。如下
S | X | |
S | 是 | 否 |
X | 否 | 否 |
舉個例子,如果有一個事務針對某行啓動了一個共享鎖S,那麼另一個事務也希望啓動共享鎖S要讀改行,那是暢通無阻的,但是如果另一個事務希望啓動X鎖去修改,那麼會被阻塞,直到S鎖釋放。
意向鎖
行鎖是細粒度地鎖。在添加行鎖之前,爲了效率,還要添加粗粒度的鎖-意向鎖,代表着我將要加哪一塊數據鎖了。mysql的意向鎖比較簡單,就是表級別的,如下:
IS | 意向共享 | 事務將要進一步對數據加S鎖 |
IX | 意向排他 | 事務將要進一步對數據加X鎖 |
他們之間的兼容性如下:
IS | IX | S | X | |
IS | Y | Y | Y | N |
IX | Y | Y | N | N |
S | Y | N | Y | N |
X | N | N | N | N |
事務中的讀
1.鎖定讀:
由於事務具有隔離性,所以事務內讀取數據有可能不是最新的。那麼如何在事務裏每次都能夠讀取到最新的數據呢?其實依據上面的知識就可以,
這需要了解lock in share mode和for update的用法,其中lock in share mode開啓了S鎖,for update開啓了X鎖。
大概如下sql語句在事務中開啓了S鎖:
select name from user where id = 1 lock in share mode
那麼由於兼容性問題,不管是lock in share mode還是for update,在遇到其他X鎖時,都會被阻塞,直到其他X鎖釋放,便獲取到了最新的數據,並且給改行加上S/X鎖。
那麼這就是所謂的一致性鎖定讀。讀的就是最新的。
2.非鎖定讀
在面對事務中普通的讀,讀出來的又是什麼樣的呢?
這個要看事務的隔離級別了。
如果隔離級別是repatable,這是innodb的默認隔離級別,讀出來的是當前事務開啓時的快照。所以即使有其他事務修改,依然讀的是老數據。
如果隔離級別 是read commited,讀出來的是所有事務裏面最新提交的快照。以至於這能產生幻讀。
鎖的算法
innodb鎖的算法主要有三種:
record lock行鎖,這是一種基礎算法
gap lock間隙鎖,這是一種基礎算法,跟索引息息相關的
next-key lock mysql使用的就是這種算法,結合record和gap的鎖。
這個我明白的不多,先舉例子說明下gap鎖吧:
如果某個索引key有 1 3 5 9 四個索引值。
gap會分區間(0,1)(1,3)(3,5)(5,9)(9,...)
注意區間是小括號,都不包括區間點。
如果此時要鎖定3,gap鎖其實不會去鎖定3,而是會鎖定(1,3)這個區間,是區間點前面那個區間,注意不包括3這個區間點.
但next-key是升級版,如果要鎖定3,nextkey會鎖定(1,3】和(3,5),這相當於包括了3以及前後兩個區間,這鎖了一大片區域。我們知道這一大片區域實際上是不存在的,是數據庫缺少的記錄,如果要加鎖,那就只能是爲了insert語句,那麼gap的目的就呼之欲出了,就是爲了數據插入的串行化。
另外,如果索引是唯一索引,next-key會降級爲record lock,不再加區間,而是隻有該行。
鎖超時
加鎖是有時間限制的,如果超時了就釋放掉,也可以設置超時回滾。
innodb_lcok_wait_timeout=60 動態
innodb_rollback_on_timeout=OFF 靜態
死鎖
怎麼產生死鎖?如下AB兩個操作
A:
begin;
select * from user where id = 1 for update
B:
begin;
select * from user where id = 2 for update
select * from user where id = 1 for update //B被鎖
A:
select * from user where id = 2 for update //A被鎖
通過上面有超時時間,我們可以知道即使是死鎖,到了超時時間就自動釋放了,其實並不影響什麼,但是在併發裏,如果什麼都不做的話會嚴重影響性能。所以innodb就做了一個自動檢測死鎖的機制,一旦發生死鎖,立即檢測到並報異常,且必然回滾。
innodb檢測死鎖的機制是採用環形檢測
鎖的表
怎麼排查鎖,很好的是,innodb下有專門的表存放鎖:
information_schema.INNODB_TRX
information_schema.INNODB_LOCKS
information_schema.INNODB_LOCK_WAITS