事務(wù)隔離級(jí)別
- 讀未提交(read uncommitted)
讀未提交是指,一個(gè)事務(wù)還沒(méi)提交時(shí)诱担,它做的變更就能被別的事務(wù)看到。 - 讀提交(read committed)
讀提交是指,一個(gè)事務(wù)提交之后溢陪,它做的變更才會(huì)被其他事務(wù)看到。 - 可重復(fù)讀(repeatable read)
可重復(fù)讀是指睛廊,一個(gè)事務(wù)執(zhí)行過(guò)程中看到的數(shù)據(jù)形真,總是跟這個(gè)事務(wù)在啟動(dòng)時(shí)看到的數(shù)據(jù)
是一致的。當(dāng)然在可重復(fù)讀隔離級(jí)別下超全,未提交變更對(duì)其他事務(wù)也是不可見(jiàn)的 - 串行化(serializable)
串行化咆霜,顧名思義是對(duì)于同一行記錄,“寫(xiě)”會(huì)加“寫(xiě)鎖”嘶朱,“讀”會(huì)加“讀鎖”蛾坯。當(dāng)
出現(xiàn)讀寫(xiě)鎖沖突的時(shí)候,后訪(fǎng)問(wèn)的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成疏遏,才能繼續(xù)執(zhí)行脉课。
事務(wù)隔離級(jí)別練習(xí)
啟動(dòng)兩個(gè)窗口
準(zhǔn)備語(yǔ)句
create database mysql45救军;
use mysql45;
查看當(dāng)前的事務(wù)隔離級(jí)別
mysql> show variables like 'tx_isolation'; # (我電腦是phpstudy自帶的mysql版本是5.5倘零。5.7引入了transaction_isolation唱遭,所以用show variables like 'transaction_isolation'; )或select @@tx_isolation;
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
既然是 REPEATABLE-READ
所以我先練習(xí)的是可重復(fù)讀。
A表示左邊窗口呈驶。B表示右邊窗口拷泽。
讀未提交
設(shè)置隔離級(jí)別的方式set tx_isolation = 'read-uncommitted';
B還沒(méi)有commit事務(wù)的時(shí)候,A事務(wù)就能查出剛insert 的數(shù)據(jù)袖瞻,也能查出update之后的數(shù)據(jù)司致。
當(dāng)B commit之后,當(dāng)然A查詢(xún)的結(jié)果不變聋迎。
讀提交
set tx_isolation = 'read-committed';
B未commit即便插入了數(shù)據(jù)或者更新元數(shù)據(jù)脂矫;A事務(wù)查詢(xún)的結(jié)果是一致的。
B commit 之后砌庄;A事務(wù)查詢(xún)到了B commit后的結(jié)果羹唠。
可重復(fù)讀
set tx_isolation = 'repeatable-read';
B不commit即便插入了數(shù)據(jù)或者更新元數(shù)據(jù);A事務(wù)查詢(xún)的結(jié)果是一致的娄昆。(這點(diǎn)跟讀提交
是相同的)
B commit佩微,A事務(wù)查詢(xún)?nèi)匀皇且恢碌摹?/p>
串行化
set tx_isolation = 'serializable';
A 先操作語(yǔ)句,B會(huì)阻塞住萌焰。會(huì)用到鎖哺眯。
或者B先操作語(yǔ)句會(huì)阻塞住A。
A commit之后扒俯,B不在阻塞就查到了提交的數(shù)據(jù)了奶卓。
begin/start transaction 命令并不是一個(gè)事務(wù)的起點(diǎn),在執(zhí)行到它們之后的第一個(gè)操作InnoDB 表的語(yǔ)句(第一個(gè)快照讀語(yǔ)句)撼玄,事務(wù)才真正啟動(dòng)夺姑。如果你想要馬上啟動(dòng)一個(gè)事務(wù),可以使用 start transaction with consistent snapshot 這個(gè)命令掌猛。
“start transaction with consistent snapshot; ”的意思是從這個(gè)語(yǔ)句開(kāi)始盏浙,創(chuàng)建一個(gè)持續(xù)整個(gè)事務(wù)的一致性快照。所以荔茬,在讀提交隔離級(jí)別下废膘,這個(gè)用法就沒(méi)意義了,等效于普通的 start transaction慕蔚。
事務(wù)的啟動(dòng)方式
不同時(shí)刻啟動(dòng)的事務(wù)有不同的read-view丐黄,對(duì)同一條記錄操作,會(huì)產(chǎn)生多個(gè)版本(回滾段)孔飒,就是數(shù)據(jù)庫(kù)的多版本并發(fā)控制(MVCC)灌闺。
select @@autocommit; # 或show variables like 'autocommit'; 我的默認(rèn)為開(kāi)啟
- 顯式啟動(dòng)事務(wù)語(yǔ)句艰争, begin 或 start transaction。配套的提交語(yǔ)句是 commit桂对,回滾語(yǔ)
句是 rollback园细。 - set autocommit=0,這個(gè)命令會(huì)將這個(gè)線(xiàn)程的自動(dòng)提交關(guān)掉接校。意味著如果你只執(zhí)行一個(gè) select 語(yǔ)句,這個(gè)事務(wù)就啟動(dòng)了狮崩,而且并不會(huì)自動(dòng)提交蛛勉。這個(gè)事務(wù)持續(xù)存在直到你主動(dòng)執(zhí)行 commit 或 rollback 語(yǔ)句,或者斷開(kāi)連接睦柴。
建議 autocommit 為1诽凌。通過(guò)顯式語(yǔ)句啟動(dòng)事務(wù)。
長(zhǎng)事務(wù)
長(zhǎng)事務(wù)意味著系統(tǒng)里面會(huì)存在很老的事務(wù)視圖坦敌。由于這些事務(wù)隨時(shí)可能訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)里面的
任何數(shù)據(jù)侣诵,所以這個(gè)事務(wù)提交之前,數(shù)據(jù)庫(kù)里面它可能用到的回滾記錄都必須保留狱窘,這就
會(huì)導(dǎo)致大量占用存儲(chǔ)空間杜顺。
除了對(duì)回滾段的影響,長(zhǎng)事務(wù)還占用鎖資源蘸炸,可能拖垮整個(gè)庫(kù)躬络。
制造一個(gè)長(zhǎng)事務(wù)。B窗口begin 執(zhí)行一條語(yǔ)句搭儒。在A(yíng)中查穷当。
你可以在 information_schema 庫(kù)的 innodb_trx 這個(gè)表中查詢(xún)長(zhǎng)事務(wù)。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60; // 大于60s淹禾。
我問(wèn)了下DBA馁菜,他們監(jiān)控的長(zhǎng)事務(wù)就是這張表。
有次有一個(gè)小伙伴查數(shù)據(jù)铃岔,沒(méi)提交就放著汪疮。
參考資料:
- 《mysql45講》03 事務(wù)隔離:為什么你改了我還看不見(jiàn)?(筆記來(lái)源)
- 《mysql tx_isolation》https://blog.csdn.net/u012807459/article/details/52174601
- 《<MySQL實(shí)戰(zhàn)45講>1~15講 —丁奇大大德撬,學(xué)習(xí)筆記 》https://blog.csdn.net/zxcc1314/article/details/84842650
- 《MySQL · 源碼分析 · InnoDB的read view铲咨,回滾段和purge過(guò)程簡(jiǎn)介》https://yq.aliyun.com/articles/560506