四種隔離級別
隔離級別 | 臟讀 | 不可重復讀 | 幻讀 |
---|---|---|---|
READ_UNCOMMITED | Yes | Yes | Yes |
READ_COMMITED | No | Yes | Yes |
REPEATABLE_READ | No | No | Yes |
SERIALIZABLE | No | No | No |
可以通過以下語句查看事務級別:
select @@tx_isolation;
臟讀
臟讀指的是一個事務可以讀取其他正在運行的事務還沒有提交的修改羔杨。
不可重復讀
不可重復讀指的是一個事務內連續(xù)讀卻得到不同的結果捌臊,原因是同時有其他事務更新了我們正在讀取的數據《挡模可重復讀是指一個事務內讀取多次理澎,得到同樣的數據,并且此時的數據就是事務開始時的數據曙寡,無論是否有其他事務修改了這部分數據都不對當前事務的讀取結果產生影響糠爬。
幻讀
幻讀指的是事務并行執(zhí)行的時候發(fā)生的一種現象,是一個事務讀取了其他事務已提交的新增數據或刪除數據举庶。例如第一個事務對一個表的所有數據進行修改执隧,同時第二個事務向表中插入一條新數據。那么操作第一個事務的用戶就發(fā)現表中還有沒有修改的數據行户侥,就像發(fā)生了幻覺一樣镀琉。四種事務隔離級別中只有SERIALIZABLE能夠解決幻讀。它和不可重復讀非常類似蕊唐,兩者的區(qū)別是:
不可重復讀強調的是數據被其他事務修改屋摔,幻讀強調的其他事務新增或刪除的數據。
栗子
首先創(chuàng)建一張表用來測試:
CREATE TABLE `account` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `UK_NAME` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表結構
約束
READ_UNCOMMITED
臟讀
- 執(zhí)行
select * from account;
替梨,此時數據庫沒有數據钓试。 - 關閉事務的自動提交功能
SET autocommit = 0;
。 - 執(zhí)行
insert into account(name) values ('admin');
副瀑。 - 另開一個事務弓熏,設置事務級別為
READ UNCOMMITTED
:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
。 - 4中的事務執(zhí)行
select * from account;
糠睡,此時應該可以看到3中插入的數據挽鞠,因為3中的事務還沒有提交,因此此時是臟讀。
事務A | 事務B |
---|---|
select * from account; | |
SET autocommit = 0; | |
insert into account(name) values ('admin'); | |
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | |
select * from account; |
幻讀
- 關閉當前事務A自動提交功能
SET autocommit = 0;
信认。 - 設置事務A的隔離級別為
READ UNCOMMITTED;
:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
串稀。 - 執(zhí)行
select * from account;
,此時數據庫沒有數據狮杨。 - 另開一個事務B母截,執(zhí)行
insert into account(name) values ('admin');
并提交。 - 對事務A而言橄教,步驟3中的select語句沒有選出任何數據清寇,因此事務A認為可以正確的插入,通過事務A再次執(zhí)行
insert into account(name) values ('admin');
护蝶,此時發(fā)現唯一鍵沖突了华烟,就像發(fā)生了幻覺一樣〕只遥幻讀主要是因為并發(fā)寫入造成的盔夜。
事務A | 事務B |
---|---|
SET autocommit = 0; | |
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | |
select * from account; | |
insert into account(name) values ('admin'); |
不可重復度讀
- 首先執(zhí)行
insert into account(name) values ('admin');
插入一條數據。 - 設置事務A的隔離級別為
READ UNCOMMITTED;
:SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
堤魁。 - 關閉事務A自動提交功能
SET autocommit = 0;
- 執(zhí)行
select * from account;
喂链,此時數據庫有一條name
是admin
的數據。 - 另開一個事務B妥泉,執(zhí)行
update account set name = 'admin2';
并提交椭微。 - 使用事務A再次重復步驟4,會發(fā)現
name
變成了admin2
盲链。
事務A | 事務B |
---|---|
insert into account(name) values ('admin'); | |
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | |
SET autocommit = 0; | |
select * from account; | |
update account set name = 'admin2'; | |
select * from account; |
READ_COMMITED
臟讀
- 執(zhí)行
select * from account;
蝇率,此時數據庫沒有數據。 - 關閉事務的自動提交功能
SET autocommit = 0;
刽沾。 - 執(zhí)行
insert into account(name) values ('admin');
本慕。 - 另開一個事務,設置事務級別為
READ COMMITTED
:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
侧漓。 - 4中的事務執(zhí)行
select * from account;
锅尘,此時無法看到3中插入的數據,因為3中的事務還沒有提交火架。 - 提交3中的事務鉴象。
- 用4中的事務再次執(zhí)行
select * from account;
忙菠,發(fā)現可以看到3中插入的數據何鸡。
事務A | 事務B |
---|---|
select * from account; | |
SET autocommit = 0; | |
insert into account(name) values ('admin'); | |
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; | |
select * from account; | |
commit; | |
select * from account; |
REPEATABLE_READ
可重復讀
- 首先執(zhí)行
insert into account(name) values ('admin');
插入一條數據。 - 設置當前事務A的隔離級別為
REPEATABLE_READ;
:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
牛欢。 - 關閉事務A自動提交功能
SET autocommit = 0;
- 執(zhí)行
select * from account;
骡男,此時數據庫有一條name
是admin
的數據。 - 另開一個事務B傍睹,執(zhí)行
update account set name = 'admin2';
并提交隔盛。 - 使用事務A再次重復步驟4犹菱,會發(fā)現
name
依然是admin
。
事務A | 事務B |
---|---|
insert into account(name) values ('admin'); | |
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; | |
SET autocommit = 0; | |
select * from account; | |
update account set name = 'admin2'; | |
select * from account; |
SERIALIZABLE
幻讀
- 關閉當前事務A自動提交功能
SET autocommit = 0;
吮炕。 - 設置事務A的隔離級別為
SERIALIZABLE;
:SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
腊脱。 - 執(zhí)行
select * from account;
,此時數據庫沒有數據。 - 另開一個事務B,執(zhí)行
insert into account(name) values ('admin');
并提交钞馁,此時可以發(fā)現事務B被卡住验毡,無法提交。 - 再回到事務A成榜,執(zhí)行
commit;
,發(fā)現剛才掛起的事務B已提交,我們可以看到事務被串行化執(zhí)行了佑女,不會有并發(fā)問題,因此也不會有幻讀的問題谈竿。
事務A | 事務B |
---|---|
SET autocommit = 0; | |
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; | |
select * from account; | |
insert into account(name) values ('admin'); | |
commit; |