Innodb 的事物隔離級別實現原理(一)

一 兩段鎖協議

由於數據庫中有大量的併發訪問,爲了預防死鎖,通常推薦使用一次封鎖法,就是在方法的開始階段預先知道使用哪些數據,而後所有鎖住,在方法運行以後在解鎖。能夠避免死鎖。可是數據庫並不知道要用到哪些數據。數據庫

數據庫遵循兩段鎖協議,將事物分紅兩個階段。加鎖階段和解鎖階段。併發

  加鎖階段:該階段能夠進行加鎖操做,在任何數據進行讀以前,都要申請並得到S鎖(共享鎖)。在寫操做以前要得到X鎖。加鎖不成功,則事物進入等待狀態,直到加鎖成功才繼續執行。性能

 

事務加鎖/解鎖處理spa

begin; insert into test .....加insert對應的鎖rest

update test set...加update對應的鎖索引

delete from test ....加delete對應的鎖事務

commit;it

事務提交時,同時釋放insert、update、delete對應的鎖。io

這種方式沒法避免死鎖,可是兩段鎖能夠保證事物的併發調度是串行的。table

二 事物的四種隔離級別

  

在RC 這個隔離級別,數據的讀取都是不加鎖的,可是數據的寫入,修改,刪除是須要加鎖的。

事務A 事務B
begin; begin;
update class_teacher set class_name='初三二班' where teacher_id=1; update class_teacher set class_name='初三三班' where teacher_id=1;
  ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
commit;

teacher_id 加了索引,鎖住的是teacher_id 這一行,若是沒有索引,鎖住是是整個表。但實際使用過程當中,MySql作了一些改進,在MySQL  Server過濾條件發現不知足後,會調用unlock_row 方法把不知足條件的記錄釋放鎖 (違背了二段鎖協議的約束)。這樣作,保證了最後只會持有知足條件記錄上的鎖,可是每條記錄的加鎖操做仍是不能省略的。

 

RR 隔離級別

事務A 事務B 事務C
begin;

begin;

begin;

select id,class_name,teacher_id from class_teacher where teacher_id=1;

id class_name teacher_id
1 初三二班 1
2 初三一班 1
   
 

update class_teacher set class_name='初三三班' where id=1;

commit;
 
    insert into class_teacher values (null,'初三三班',1);commit;

select id,class_name,teacher_id from class_teacher where teacher_id=1;

id class_name teacher_id
1 初三二班 1
2 初三一班 1

 

不少人容易搞混不可重複讀和幻讀,確實這二者有些類似。但不可重複讀重點在於update和delete,而幻讀的重點在於insert。

在可重複讀中,該SQL第一次讀取到數據後就將這些數據加鎖,其它事務沒法修改這些數據,就能夠實現可重複讀了。可是沒法鎖住insert 數據。

三  MVCC協議

 mySql 這種成熟的數據庫出於性能考慮,使用了基於樂觀鎖的爲理論基礎的MVCC(協議)

在InnoDB中,會在每行數據後添加兩個額外的隱藏的值來實現MVCC,這兩個值一個記錄這行數據什麼時候被建立,另一個記錄這行數據什麼時候過時

相關文章
相關標籤/搜索