知識點傳送門:👇
MySQL默認隔離級別:可重複讀(Repeatable read)
來自靈魂的拷問:👇
~ 爲什麼 MySQL 選擇 "可重複讀" 作爲默認隔離級別?
正文:👇
我們先來思考一個問題,在Oracle,SqlServer中都是選擇讀已提交(Read Commited)作爲默認的隔離級別,
爲什麼Mysql不選擇讀已提交(Read Commited)作爲默認隔離級別,而選擇可重複讀(Repeatable Read)作爲默認的隔離級別呢?
原因如下:👇
這個是有歷史原因的,當然要從我們的主從複製開始講起了!
主從複製,是基於什麼複製的?
是基於binlog複製的!這裏不想去搬binlog的概念了,就簡單理解爲binlog是一個記錄數據庫更改的文件吧。
binlog有幾種格式? OK,三種,分別是
statement:記錄的是修改SQL語句
row:記錄的是每行實際數據的變更
mixed:statement和row模式的混合
那Mysql在5.0這個版本以前,binlog只支持STATEMENT這種格式!
而這種格式在讀已提交(Read Commited)這個隔離級別下主從複製是有bug的,因此Mysql將可重複讀(Repeatable Read)作爲默認的隔離級別!
接下來,就要說說當binlog爲STATEMENT格式,且隔離級別爲讀已提交(Read Commited)時,有什麼bug呢?
如下圖所示,在主(master)上執行如下事務:
此時在主(master)上執行下列語句:
select * from test;
輸出如下:
+---+ | b | +---+ | 3 | +---+ 1 row in set
但是,你在此時在從(slave)上執行該語句,得出輸出如下:
Empty set
這樣,你就出現了主從不一致性的問題!原因其實很簡單,就是在master上執行的順序爲先刪後插!
而此時binlog爲STATEMENT格式,它記錄的順序爲先插後刪!從(slave)同步的是binglog,因此從機執行的順序和主機不一致!就會出現主從不一致!
如何解決?
解決方案有兩種!
1):隔離級別設爲可重複讀(Repeatable Read),在該隔離級別下引入間隙鎖。當Session 1執行delete語句時,會鎖住間隙。那麼,Ssession 2執行插入語句就會阻塞住!
2):將binglog的格式修改爲row格式,此時是基於行的複製,自然就不會出現sql執行順序不一樣的問題!奈何這個格式在mysql5.1版本開始才引入。
因此由於歷史原因,mysql將默認的隔離級別設爲可重複讀(Repeatable Read),保證主從複製不出問題!
那麼,當我們瞭解完mysql選可重複讀(Repeatable Read)作爲默認隔離級別的原因後,
接下來我們將其和讀已提交(Read Commited)進行對比;
來說明爲什麼在互聯網項目爲什麼將隔離級別設爲讀已提交(Read Commited)!
對比 ok,我們先明白一點!項目中是不用讀未提交(Read UnCommitted)和串行化(Serializable)兩個隔離級別;
原因有二 :
採用讀未提交(Read UnCommitted),一個事務讀到另一個事務未提交讀數據,這個不用多說吧,從邏輯上都說不過去!
採用串行化(Serializable),每個次讀操作都會加鎖,快照讀失效,一般是使用mysql自帶分佈式事務功能時才使用該隔離級別!
(筆者從未用過mysql自帶的這個功能,因爲這是XA事務,是強一致性事務,性能不佳!互聯網的分佈式方案,多采用最終一致性的事務解決方案!)
人生無常大腸包小腸