mysql 事務有四種隔離級別,分別是:讀未提交READ UNCOMMITTED 、讀提交 READ COMMITTED、可重復讀REPEATABLE READ、串行化SERIALIZABLE。下面我們分別看下不同隔離級別下對事務的影響。
首先查看mysql的隔離級別:
show variables like 'transaction_isolation';
我們看到mysql的默認隔離級別是可重復讀,下面設置mysql的隔離級別為讀未提交。這里我們只設置當前會話的隔離級別:
set session transaction isolation level READ UNCOMMITTED;
然后我們在數據庫中建立這樣一張表 staffs:
CREATE TABLE `staffs` ( `id` int DEFAULT NULL, `name` char(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `age` int DEFAULT NULL, KEY `id_name_age_index` (`id`,`name`,`age`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
然后預置一部分數據:
讀未提交
接下來我們進行一個操作,來演示讀未提交的隔離級別。
事務A執行:
BEGIN; select * from staffs where id =1;
得到如下結果:
事務B執行:
BEGIN; select * from staffs where id =1; update staffs set age=11 where id=1;
事務B 執行完update操作后,在事務A中,再查詢下id=1的值,如下所示:
可以看到,此時事務A已經讀到了事務B的修改,注意此時事務B尚未提交commit。 這個也就是我們所說的臟讀。
讀已提交
接下來演示下讀提交,修改當前會話的隔離級別為READ COMMITTED讀提交
set session transaction isolation level READ COMMITTED;
然后按照上面的順序執行:
發現,在讀提交的隔離級別下,當事務B修改完數據尚未提交時,事務A是無法讀取到修改的數據的。當事務B提交事務后,事務A才可以看到修改的結果。
可重復讀
修改當前會話的隔離級別為可重復讀:
set session transaction isolation level REPEATABLE READ;
還按照上面的事務執行順序執行:
可以發現,當事務B提交后,事務A查詢的結果依然是事務A開啟時讀到的數據,這就是所謂的可重復讀,也就是說事務開啟時讀到的數據,在事務提交前,是一致的,不會因為外面事務的修改提交而改變開啟事務前讀到的值。
串行化
設置數據庫的隔離級別為SERIALIZABLE,然后按照圖下的步驟執行操作
當事務A 查詢id為1的數據行后,事務B嘗試去update id=1的數據行,就會被阻塞住。只有當事務Acommit 后,事務B才執行成功(可以看到步驟2執行了22秒)。當事務A再進行查詢ID=1的數據時,發現age還是13,而事務B查詢已經變成了14.這是因為事務B還沒有提交,對於串行化,對於同一行數據,必須一個事務一個事務順序執行,當事務B提交后,事務A再查詢,就變成了14.

來源:稀土掘金