mysql事務隔離級別和鎖

白露非霜發表於2021-06-30

1.資料庫的鎖

從效能上分為樂觀鎖和悲觀鎖:樂觀鎖是利用版本號,比如資料欄位新增一個版本號欄位,操作的時候進行版本的比對,需要開發者自己實現;悲觀鎖就是在運算元據時,認為此操作會出現資料衝突,所以在進行每次操作時都要通過獲取鎖才能進行對相同資料的操作,這點跟java中的synchronized很相似,因此悲觀鎖需要耗費較多的時間。悲觀鎖是由資料庫自己實現了的,執行CRUD操作都會涉及到。

從對對資料庫的操作型別上面可以分為讀鎖和寫鎖,都屬於悲觀鎖:讀鎖也叫共享鎖,針對同一份資料,多個讀操作可以同時進行,但是寫操作不允許。寫鎖也叫排它鎖,當寫操作完成時,讀寫都不允許

從資料庫的操作粒度上可以分為表鎖和行鎖InnoDB支援行鎖,myISAM不支援行鎖。

表鎖每次操作鎖住整張表。開銷小,加鎖快(直接鎖住整張表);不會出現死鎖;鎖定粒度大,發生鎖衝 突的概率最高,併發度最低;

行鎖每次操作鎖住一行資料。開銷大,加鎖慢(需要定位到那條資料);會出現死鎖(兩個事務分別操作AB兩條資料,事務一先操作B,再操作A,事務二先操作A,再操作B,這個時候就可能出現死鎖);鎖定粒度最小,發生鎖衝突的概率最低,併發度最高。

 

加表鎖:lock table 1 read(write), 2 read/write;

檢視錶鎖: show open tables;  結果中In_use欄位為1,表示加了表鎖

 

釋放當前會話加的表鎖unlock tables;

 

MyISAM在執行查詢語句(SELECT),會自動給涉及的所有表加讀鎖,在執行增刪改操作前,會自動給涉及的表加寫鎖InnoDB支援事務,因此它的鎖和事務的隔離級別有一定關係。

 

2.資料庫事務和隔離級別

2.1 事務

InnoDB支援事務而MyISAM是不支援事務的。

我們都知道事務具有四大屬性——ACID

原子性Atomicity:事務看做是一個原子操作,因此其對資料的修改,要麼全都執行成功,要麼都不成功。

一致性Consistent:事務開始和結束時的資料都是一致的 。

隔離性Isolation:事務處理中的資料狀態對外部是不可見的,反之也無法獲取到其他事務處理中的資料狀態。

永續性Durable:事務提交之後,對資料的修改時永久性的。

 

2.2併發事務帶來的問題

更新丟失:當多個事務更新同一行資料時,因為隔離性的存在,彼此都不知道其他的事務的存在,就會導致最後一個提交的事務,覆蓋了其他事務提交的資料。

髒讀:事務A正在對一條記錄修改,事務B讀了A正在修改的資料。但是此時事務A並未提交。後續因為問題事務A可能回滾,那麼事務B讀到的資料就是無效的髒資料。同時也破壞了事務的一致性的要求。

不可能重複讀:在一次事務中,多次執行同樣的查詢條件,獲取到的結果不一致,也就是讀到了其他事務的修改的資料。不符合事務的隔離性

幻讀:和不可重複讀不一樣的是幻讀是讀取到了新增的資料。

正因為存在以上問題,所以就就需要資料庫提供一定的機制來解決這些問題。

 

2.3事務隔離級別

事務隔離級別 髒讀 不可重複讀 幻讀
讀未提交 可能 可能 可能
讀已提交 不可能 可能 可能
可重複讀 不可能 不可能 可能
序列化 不可能 不可能 不可能

 

 

 

資料庫的事務隔離越嚴格,併發副作用越小,但付出的代價也就越大,因為事務隔離實質上就是使事務在一定程度上“序列化”進行,這顯然與“併發”是矛盾的。 同時,不同的應用對讀一致性和事務隔離程度的要求也是不同的,比如許多應用 對“不可重複讀"和“幻讀”並不敏感,可能更關心資料併發訪問的能力,所以大多數時候我們都會採用的可重複讀的事務隔離級別。

 

3.InnoDB的行鎖

 

前面有說MyISAM會根據執行的操作對資料加表鎖(讀鎖/寫鎖)。InnoDB有所不同,在非序列化的隔離級別下面select語句不會加鎖,但是updateinsertdelete會根據條件加行鎖。且行鎖是加在索引上面的,如果這些語句沒有走索引,那麼也會加表鎖。

如果條件是範圍,那麼該範圍內的所有行,包括每行記錄所在的間隙區間都會被加上鎖,就算該行資料還未被插入也會被加鎖,這就是所謂的間隙鎖,間隙鎖在可重複讀隔離級別下面才會生效。

比如說A表現有的id1,2,3,4,5,10,20;那麼間隙區間就有5-10,10-20,20-正無窮三個區間。我們執行update A set XXX= 'XXX' where id > 6 and id <16; 首先[6,16]這個範圍的資料會被加鎖,然6是落在5-10這個間隙區間的,這個區間的資料也會加鎖,16是落在10-20這個間隙區間,這個區間的記錄也會被加鎖,所以執行上述sql(5,16]左開又閉,這個區間的資料都會被加鎖。如果執行的update A set XXX= 'XXX' where id > 6 and id <21;那麼(5,正無窮) 都會被加鎖,所以這個點還需要注意一下。

因此我們應該:

1.儘可能讓所有資料查詢,修改都通過索引來完成,避免無索引行鎖升級為表鎖

2.儘可能減少條件範圍,縮小鎖的範圍,儘量避免間隙鎖

3.儘量控制事務大小,減少鎖定資源量和時間長度,涉及事務加鎖的sql儘量放在事務最後執行

 

相關文章