MySQL并發(fā)事務(wù)問題及隔離級別操作演示(附詳細圖文)
舉例演示了MySQL的并發(fā)事務(wù)問題,以及四個事務(wù)隔離級別的區(qū)別,例子直接跳轉(zhuǎn)標(biāo)題3.
1.并發(fā)事務(wù)問題
(1)臟讀 (Dirty Read)
問題描述:一個事務(wù)讀取了另一個未提交事務(wù)修改過的數(shù)據(jù)
示例:
事務(wù)A修改了某行數(shù)據(jù)但未提交
事務(wù)B讀取了事務(wù)A修改后的數(shù)據(jù)
事務(wù)A回滾,事務(wù)B讀取的數(shù)據(jù)就是無效的"臟數(shù)據(jù)"
(2)不可重復(fù)讀 (Non-repeatable Read)
問題描述:在同一事務(wù)內(nèi),多次讀取同一數(shù)據(jù)返回不同結(jié)果(因為其他事務(wù)修改并提交了該數(shù)據(jù))
示例:
事務(wù)A第一次讀取某行數(shù)據(jù)
事務(wù)B修改了該行數(shù)據(jù)并提交
事務(wù)A再次讀取同一行數(shù)據(jù),發(fā)現(xiàn)數(shù)據(jù)已改變
(3) 幻讀 (Phantom Read)
問題描述:在同一事務(wù)內(nèi),多次查詢返回不同的行集合(因為其他事務(wù)新增或刪除了數(shù)據(jù))
示例:
事務(wù)A查詢表中符合某條件的行
事務(wù)B插入新的符合該條件的行并提交
事務(wù)A再次查詢,發(fā)現(xiàn)多出了"幻影行"
2.事務(wù)隔離級別
我們可以通過給事務(wù)設(shè)置隔離級別來解決上述并發(fā)問題
MySQL 提供了四種隔離級別
| 隔離級別 | 臟讀 | 不可重復(fù)讀 | 幻讀 | 說明 |
|---|---|---|---|---|
| READ UNCOMMITTED (讀未提交) | 可能 | 可能 | 可能 | 最低隔離級別,性能最好但問題最多 |
| READ COMMITTED (讀已提交) | 可能 | 可能 | 不可能 | 只讀取已提交的數(shù)據(jù),Oracle默認(rèn)級別 |
| REPEATABLE READ (可重復(fù)讀) | 可能 | 不可能 | 不可能 | MySQL默認(rèn)級別,確保同一事務(wù)內(nèi)讀取一致 |
| SERIALIZABLE (串行化) | 不可能 | 不可能 | 不可能 | 最高隔離級別,性能最差但最安全 |
事務(wù)隔離級別的相關(guān)操作
查看當(dāng)前隔離級別
SELECT @@transaction_isolation; -- 或 SHOW VARIABLES LIKE 'transaction_isolation';
設(shè)置隔離級別
可以設(shè)置全局級別或會話級別:
-- 設(shè)置全局隔離級別 SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 設(shè)置當(dāng)前會話隔離級別 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 設(shè)置下一個事務(wù)的隔離級別 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3.操作演示
(1).準(zhǔn)備數(shù)據(jù)
首先,準(zhǔn)備一個簡單的數(shù)據(jù)表做演示
這里是一個簡單的賬戶表
create table account
(
user_name varchar(20) not null,
money double null,
id int auto_increment
primary key
);
# 添加數(shù)據(jù)
insert into account values ('jack',8000,1),('mary',8000,2);
因為要演示并發(fā)問題,所以,我們直接使用cmd打開兩個窗口演示

找到 上面表所在的數(shù)據(jù)庫
(2).臟讀
我們先演示,臟讀:一個事務(wù)讀取了另一個未提交事務(wù)修改過的數(shù)據(jù)
先設(shè)置左窗口的事務(wù)隔離級別為 read uncommitted
set session transaction isolation level read uncommitted ;

然后在左窗開啟一個事務(wù),查詢一下 account表的數(shù)據(jù):

接著在右窗開啟一個事務(wù),修改 一下 account表的數(shù)據(jù):

注意,這時我們并沒有commit 提交右窗修改的數(shù)據(jù)
但是,我們再在左窗查詢 數(shù)據(jù),卻發(fā)現(xiàn)查詢到的數(shù)據(jù)已經(jīng)修改了

這就體現(xiàn)了臟讀問題,右窗的事務(wù),訪問到了左窗事務(wù)還未提交的數(shù)據(jù)!
演示完成,別忘了結(jié)束兩邊的事務(wù),再進行后續(xù)操作

我們把右窗事務(wù)隔離級別修改為 readcommited 就可以避免臟讀問題
就是下面 不可重復(fù)讀的操作演示,不再贅述
右窗:

左窗:

(3.1).不可重復(fù)讀
右窗事務(wù)隔離級別設(shè)置為 readcommited
開啟一個事務(wù),查詢一下數(shù)據(jù)

在左窗開啟一個事務(wù),修改表中數(shù)據(jù)

左窗還未提交zai再次在右窗查詢,發(fā)現(xiàn)數(shù)據(jù)沒有變化,也就是解決了 臟讀問題

左窗提交數(shù)據(jù)后,再次在右窗查詢,發(fā)現(xiàn)數(shù)據(jù)變化了,

在右窗的一個事務(wù)過程中,出現(xiàn)了多次讀取同一數(shù)據(jù)但返回不同結(jié)果的現(xiàn)象,這就是不可重復(fù)讀
(3.2).解決不可重復(fù)讀
設(shè)置右窗事務(wù)隔離級別為REPEATABLE READ (可重復(fù)讀), 開啟一個事務(wù),查詢當(dāng)前表數(shù)據(jù)

左窗還是開啟一個事務(wù),修改表中數(shù)據(jù),這次我們直接提交!

右窗再次查詢表數(shù)據(jù),可以看到,這次左窗事務(wù)雖然已經(jīng)提交了修改,但是右窗查詢數(shù)據(jù)還是沒變。這樣一個事務(wù)里就不會出現(xiàn)多次讀取同一數(shù)據(jù)但返回不同結(jié)果的現(xiàn)象,這就解決了上面 不可重復(fù)的的問題

我們結(jié)束右窗事務(wù)后,再次查詢,則看到了最新數(shù)據(jù)

(4.1).幻讀
右窗不改變隔離級別,依舊為 repeatable read
開啟新事務(wù),查詢id為3的信息,當(dāng)前沒有id為3的人,當(dāng)然查詢不到

此時,左窗開啟一個事務(wù),插入id= 3的一條數(shù)據(jù) ,并直接提交

由于,并發(fā)執(zhí)行,之前右窗沒有查詢到id= 3的數(shù)據(jù),于是也準(zhǔn)備插入一條id= 3的數(shù)據(jù),但是由于左窗已經(jīng)插入完成,所以無法插入。如下圖

右窗再次查詢id為3的信息,但是還是查詢不到

像這樣右窗這樣,查詢時查詢不到,插入時又認(rèn)為數(shù)據(jù)已經(jīng)存在不讓插入 的現(xiàn)象 就叫 幻讀
(4.2).解決幻讀
設(shè)置右窗事務(wù)隔離級別為SERIALIZABLE (串行化),開啟事務(wù),查詢id= 4的數(shù)據(jù),沒有

左窗開啟事務(wù),插入id= 4的一條數(shù)據(jù),但是按回車后,卻沒有運行,這就是因為 右窗事務(wù)隔離級別為SERIALIZABLE (串行化)
所有事務(wù)只能串行執(zhí)行,解決了所有并發(fā)問題

只能在右窗執(zhí)行完當(dāng)前事務(wù)的全部操作后,左窗事務(wù)才能繼續(xù)!

左窗:

總結(jié)
到此這篇關(guān)于MySQL并發(fā)事務(wù)問題及隔離級別操作演示的文章就介紹到這了,更多相關(guān)MySQL并發(fā)事務(wù)及隔離級別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL count(*/column)查詢優(yōu)化的實現(xiàn)
count()是SQL中一個常用的聚合函數(shù),其被用來統(tǒng)計記錄的總數(shù),本文主要介紹了MySQL count(*/column)查詢優(yōu)化的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-09-09
mysql數(shù)據(jù)庫鎖的產(chǎn)生原因及解決辦法
這篇文章主要介紹了mysql數(shù)據(jù)庫鎖的產(chǎn)生原因及解決辦法,需要的朋友可以參考下2016-01-01

