在日常開發(fā)過程中欺旧,事務(wù)是經(jīng)常被使用的州既,然而大多數(shù)開發(fā)者并不了解事務(wù)隔離級別是什么,也不知道不同的隔離級別下使用事務(wù)時可能會發(fā)生的一些問題。
SQL標(biāo)準(zhǔn)定義的四個隔離級別為:
- READ UNCOMMITTED (讀未提交)
- READ COMMITTED (讀已提交)
- REPEATABLE READ (可重復(fù)讀)
- SERIALIZABLE (串行)
?
user表
id | name | money |
---|---|---|
1 | 小李 | 1000 |
?
READ UNCOMMITTED
事務(wù)A修改了一條數(shù)據(jù)树碱,但未提交,事務(wù)B可以讀到被事務(wù)A修改的數(shù)據(jù)涉茧,存在臟讀問題赴恨,同時也存在不可重復(fù)讀、幻讀等問題(不一一寫實際例子)伴栓。
事務(wù)A | 事務(wù)B |
---|---|
start TRANSACTION | start TRANSACTION |
update user set name = '小明' where id = 1 | - |
- | select name from user where id = 1 |
?
READ COMMITTED
解決了臟讀的情況伦连,但是當(dāng)事務(wù)A提交之后,事務(wù)B在一次事務(wù)內(nèi)讀取同一條數(shù)據(jù)會有不同的結(jié)果钳垮,存在不可重復(fù)讀的問題惑淳。
事務(wù)A | 事務(wù)B |
---|---|
start TRANSACTION | start TRANSACTION |
update user set name = '小明' where id = 1 | - |
- | select name from user where id = 1 |
COMMIT | - |
- | select name from user where id = 1 |
?
REPEATABLE READ
Mysql默認(rèn)的事務(wù)隔離級別,解決了臟讀饺窿、不可重復(fù)讀問題歧焦,同時用
next_key_lock 解決了幻讀的問題,但是有出現(xiàn)更新覆蓋的可能肚医。
事務(wù)A | 事務(wù)B |
---|---|
start TRANSACTION | start TRANSACTION |
select money into @money from user where id = 1 | select money into @money from user where id = 1 |
update user set money = @money-100 where id = 1 | - |
COMMIT | - |
- | update user set money = @money-50 where id = 1 |
- | COMMIT |
對應(yīng)實際的業(yè)務(wù)場景绢馍,就是用戶分別消費(fèi)了100元和50元,2個事務(wù)都成功了肠套,但是實際上最終賬戶只減少了50元舰涌。
解決這種情況,需要在讀取數(shù)據(jù)的時候加上排他鎖(X鎖)你稚,使2個事務(wù)變成串行操作瓷耙。如下:
事務(wù)A | 事務(wù)B |
---|---|
start TRANSACTION | start TRANSACTION |
select money into @money from user where id = 1 for update | select money into @money from user where id = 1 for update |
update user set money = @money-100 where id = 1 | - |
COMMIT | - |
- | update user set money = @money-50 where id = 1 |
- | COMMIT |
?
SERIALIZABLE
串行模式下,可以解決事務(wù)相互依賴導(dǎo)致的死鎖問題刁赖,以及REPEATABLE READ下可能出現(xiàn)的更新被覆蓋問題搁痛,但是由于不能同時執(zhí)行2個或以上的事務(wù),會使性能下降宇弛,所以大部分情況下不會選擇此模式鸡典。