MySQL 事務隔離級別

icecho發表於2020-07-03

前言

簡單來說,資料庫事務就是保證一組資料操作要麼全部成功,要麼全部失敗。在 MySQL 中,事務是在引擎層實現的。原生的 MyISAM 引擎不支援事務,也是為什麼 InnoDB 會取代它的重要原因之一。

隔離性與隔離級別

當資料庫上有多個事務同時執行的時候,根據隔離級別的不同,可能會出現髒讀、幻讀和不可重複讀。標準隔離級別包括讀未提交、讀提交、可重複讀和序列化。

讀未提交

如果用這種隔離級別,事務執行的時候會讀到其他未提交事務的資料,我們稱為髒讀。

# 客戶端 A
start transaction;
update users set name = 'hello' where id = 1;
select * from users where id = 1; # 此時可以讀到 name 已經被更新為 hello
# 客戶端 B
start transaction;
select * from users where id = 1; # 此時讀到 name 為 hello

在此隔離級別下,客戶端 B 讀到了客戶端 A 還未提交的事務即還未 commit 的事務,即產生的髒讀現象。

讀提交

如果用這種隔離級別,事務執行的時候會讀到其他已提交事務的資料,我們稱為不可重複讀。

# 客戶端 A
start transaction;
update users set name = 'hello' where id = 1;
commit;
# 客戶端 B
start transaction;
select * from users where id = 1; # 此時 name 不為 hello
# 此時 客戶端 A 完成 commit
select * from users where id = 1; # 此時 name 為 hello

在此隔離級別下,客戶端 B 讀到了客戶端 A 完成提交的事務,產生了不可重複讀現象。

可重複讀

在同一個事務裡,SELECT 語句獲得的結果是基於事務開始時間點的狀態,同一個事務中 SELECT 語句得到的結果是一樣的,但是會有幻讀現象。

# 客戶端 A
start transaction;
select * from users; # 為空
# 此時客戶端 B 完成 commit 操作
select * from users; # 還是為空
insert into users(id, name) value (1, 'hello') # 報主鍵衝突
# 客戶端 B
start transaction;
select * from users; # 為空
insert into users(id, name) values (1, 'hello');
commit;

在此隔離級別下,會產生幻讀現象。

序列化

在該事務級別下,事務都是序列順序執行的,避免了髒讀,不可重複讀,幻讀問題。

# 客戶端 A
start transaction;
insert into users(id, name) values (1, 'hello');
commit;
# 客戶端 B
start transaction;
select * from users; # 會一直阻塞住,直到客戶端 A 完成事務提交
本作品採用《CC 協議》,轉載必須註明作者和本文連結

Hello。

相關文章