MYSQL中的樂觀鎖實現 MVCC 簡析

2021-09-12 12:58:55 字數 3549 閱讀 3930

mvcc即multi-version concurrency control,中文翻譯過來叫多版本併發控制。

眾所周知,在mysql中,myisam使用的是表鎖,innodb使用的是行鎖。而innodb的事務分為四個隔離級別,其中預設的隔離級別repeatable read需要兩個不同的事務相互之間不能影響,而且還能支援併發,這點悲觀鎖是達不到的,所以repeatable read採用的就是樂觀鎖,而樂觀鎖的實現採用的就是mvcc。正是因為有了mvcc,才造就了innodb強大的事務處理能力。

innodb的mvcc,是通過在每行記錄後面儲存兩個隱藏的列來實現的,這兩個列,分別儲存了這個行的建立時間,乙個儲存的是行的刪除時間。這裡儲存的並不是實際的時間值,而是系統版本號(可以理解為事務的id),每開始乙個新的事務,系統版本號就會自動遞增,事務開始時刻的系統版本號會作為事務的id.下面看一下在repeatable read隔離級別下,mvcc具體是如何操作的。

首先建立一張表:

create table yang( 

id int primary key auto_increment,

name varchar(20)

);

假設系統的版本號從1開始.

innodb為新插入的每一行儲存當前系統版本號作為版本號。第乙個事務id為1:

start transaction; 

insert into yang values(null,'yang');

insert into yang values(null,'long');

insert into yang values(null,'fei');

commit;

對應在資料中的表如下(後面兩列是隱藏列,我們通過查詢語句並看不到)

idname

建立時間(事務id)

刪除時間(事務id)

1yang

1undefined

2long

1undefined

3fei

1undefined

innodb會根據以下兩個條件檢查每行記錄:

innodb只會查詢版本早於當前事務版本的資料行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或者修改過的.

行的刪除版本要麼未定義,要麼大於當前事務版本號(這可以確保事務讀取到的行,在事務開始之前未被刪除), 

只有條件1、2同時滿足的記錄,才能返回作為查詢結果.

innodb會為刪除的每一行儲存當前系統的版本號(事務的id)作為刪除標識.

看下面的具體例子分析: 第二個事務,id為2:

start transaction; 

select * from yang;

select * from yang;

commit;

假設1:

假設在執行這個事務id為2的過程中,剛執行到(1),這時,有另乙個事務id為3往這個表裡插入了一條資料; 第三個事務id為3;

start transaction;

insert into yang values(null,'tian');

commit;

這時表中的資料如下:

idname

建立時間(事務id)

刪除時間(事務id)

1yang

1undefined

2long

1undefined

3fei

1undefined

4tian

3undefined

然後接著執行事務2中的(2),由於id=4的資料的建立時間(事務id為3),執行當前事務的id為2,而innodb只會查詢事務id小於等於當前事務id的資料行,所以id=4的資料行並不會在執行事務2中的(2)被檢索出來,在事務2中的兩條select 語句檢索出來的資料如下:

idname

建立時間(事務id)

刪除時間(事務id)

1yang

1undefined

2long

1undefined

3fei

1undefined

假設2

假設在執行這個事務id為2的過程中,剛執行到(1),假設事務執行完事務3後,接著又執行了事務4; 

第四個事務:

start transaction; 

delete from yang where id=1;

commit;

此時資料庫中的表如下:

idname

建立時間(事務id)

刪除時間(事務id)

1yang14

2long

1undefined

3fei

1undefined

4tian

3undefined

接著執行事務id為2的事務(2),根據select 檢索條件可以知道,它會檢索建立時間(建立事務的id)小於當前事務id的行和刪除時間(刪除事務的id)大於當前事務的行,而id=4的行上面已經說過,而id=1的行由於刪除時間(刪除事務的id)大於當前事務的id,所以事務2的(2)select * from yang也會把id=1的資料檢索出來.所以,事務2中的兩條select 語句檢索出來的資料都如下:

idname

建立時間(事務id)

刪除時間(事務id)

1yang14

2long

1undefined

3fei

1undefined

innodb執行update,實際上是新插入了一行記錄,並儲存其建立時間為當前事務的id,同時儲存當前事務id到要update的行的刪除時間。 

假設3:

假設在執行完事務2的(1)後又執行,其它使用者執行了事務3,4,這時,又有乙個使用者對這張表執行了update操作: 

第5個事務:

start transaction; 

update yang set name='long' where id=2;

commit;

根據update的更新原則:會生成新的一行,並在原來要修改的列的刪除時間列上新增本事務id,得到表如下:

idname

建立時間(事務id)

刪除時間(事務id)

1yang14

2long15

3fei

1undefined

4tian

3undefined

2long

5undefined

繼續執行事務2的(2),根據select 語句的檢索條件,得到下表:

idname

建立時間(事務id)

刪除時間(事務id)

1yang14

2long15

3fei

1undefined

還是和事務2中(1)select 得到相同的結果.

mysql樂觀鎖實現 mysql樂觀鎖實現

在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 1.丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。2.髒讀 當乙個事務讀取其它完成...

mysql 樂觀鎖實現 mysql 樂觀鎖實現

一 為什麼需要鎖 併發控制 在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 1.丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。2....

mysql 樂觀鎖實現

一 為什麼需要鎖 併發控制 在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 1.丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。2....