mysql 四種隔離級別詳解

本文以一系列詳細的sql語句,使你徹底理解mysql的四種隔離級別。
下面的例子中,用到了兩個會話(session),每個session中各開啓了一個事務,分別記作session A, 事務A;session B, 事務B。

準備工作

首先新建一個表‘student’,並插入兩行數據

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

insert student(id, name) values(1, 'zhangsan'), (2, 'lisi');

表中數據如下圖:

id name
1 zhangsan
2 lisi

然後用以下sql查詢數據庫的默認隔離級別

select @@transaction_isolation; 

可以看到默認隔離級別是“可重複讀”

REPEATABLE-READ

接下來通過sql詳細地說明每一個隔離級別的含義。

read-uncommitted

驗證“讀未提交”, 首先我們開啓一個會話(session A),
設置數據庫的隔離級別爲’read-uncommitted’。

set session transaction_isolation = 'read-uncommitted';

開啓事務A

start transaction;

更新name,並查詢student表

update student set name = 'hehe';
select * from student;

結果如下:

id name
1 hehe
2 hehe

注意,當前事務A中,我們還未提交以上update語句的修改(start transaction之後,需要手動執行commit,纔是提交)
現在我們另開一個會話(session B),並設置隔離級別爲"讀未提交"。

set session transaction_isolation = 'read-uncommitted';

接下來開啓事務B,並查詢表’student’

start transaction;
select * from student;

結果如下

id name
1 hehe
2 hehe

此時,事務A和B均未提交,我們在事務B中查到了事務A中未提交的數據,此爲髒讀

read-committed

接下來驗證“讀已提交”, 首先提交以上未提交的事務A和事務B(執行commit;),並設置session A和session B的隔離級別爲“讀已提交”:

set session transaction_isolation = 'read-committed';

在session B中開啓事務B,並查詢表’student’

start transaction;
select * from student;

結果如下:

id name
1 hehe
2 hehe

在session A中開啓事務A, 並更新student

start transaction;
update student set name = 'zhangsan' where id = 1;

事務A未提交的時候,再次在事務 B中查詢student

select * from student;

結果與上面一樣:

id name
1 hehe
2 hehe

說明“讀已提交”避免了髒讀。
事務A中執行提交

commit;

事務B中再次執行查詢student

select * from student;

結果如下:

id name
1 zhangsan
2 hehe

此時,事務A已提交,事務B未提交。而事務B能讀到事務A已提交的數據,並且和前面一次查詢的結果不同了,此爲不可重複讀。“讀已提交”已經可以避免髒讀問題。

repeatable-read

接下來驗證“可重複讀”。首先提交上面的事務A和事務B,然後設置session A和session B的隔離級別是“可重複讀”:

set session transaction_isolation = 'repeatable-read';

session B中,開啓事務B並查詢student

start transaction;
select * from student;

結果如下:

id name
1 zhangsan
2 hehe

session A中開啓事務A,並插入一條數據

start transaction;
insert student (id, name)values(3, 'haha');

此時事務A未提交,在事務B中插入同樣id爲3的一行數據

insert student (id, name)values(3, 'haha');

報錯如下:

[Err] 1062 - Duplicate entry '3' for key 'PRIMARY'

再次查詢student

select * from student;

還是

id name
1 zhangsan
2 hehe

可以看出,事務B中查詢student,只有兩行數據(id是1和2),可是插入id是3的數據,卻報錯說已存在id爲3的數據,此爲幻讀。“可重複讀”已經可以避免不可重複讀問題。

serializable

這個就不驗證了,很容易理解,“串行化”可以避免幻讀問題。

總結

隔離級別 髒讀 不可重複讀 幻讀
read-uncommitted 1 1 1
read-committed 0 1 1
repeatable-read 0 0 1
serializable 0 0 0

特別說明,不可重複讀幻讀的區別不是太明顯,不可重複讀是指一個事務讀到了另一個事務提交的修改,幻讀是指一個事務感受到了另一個事務的增刪數據。也就是說前者指的是“增刪改查”中的“改”,後者指的是“增刪”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章