MySQL RR 與 鎖

引言

以前在面試準備期間寫過相關的筆記,但時間倉促,未進行詳述,對你們參考意義不大。面試

image.png

MySQL數據庫面試/開發中,事務一直是重中之重,這些知識在以前面試的時候學過,到如今也記得不太清楚了,本文帶領你們一塊兒來回顧MySQL的事務知識。數據庫

精講

前置知識

事務一般併發執行,爲了不事務併發形成的一系列問題,數據庫設計四大事務隔離級別:併發

  • READ-UNCOMMITTED
  • READ-COMMITTED
  • REPEATABLE-READ
  • SERIALIZABLE

MySQL默認的事務隔離級別是REPEATABLE-READOracle默認的
事務隔離級別是READ-COMMITTED數據庫設計

MySQL的衆多引擎中,只有InnoDB引擎支持事務與外鍵,而另外一經常使用的MyISAM引擎雖不支持事務、外鍵,但訪問速度快。測試

下圖來自:《深刻淺出MySQL數據庫開發優化與管理維護》優化

image.png

場景

咱們聊聊最難理解的REPEATABLE-READ級別。spa

READ-COMMITED隔離級別下,會出現如下問題:設計

事務A 事務B
開啓事務 開啓事務
查詢帳戶餘額爲3000元 /
/ 更新帳戶餘額爲3500元
/ 提交事務
使用相同的條件去查詢帳戶餘額,發現餘額變爲了3500元 /
提交事務 /

事務A就很蒙圈,兩次查詢結果不同,我以哪一個爲準呢?要是以3500爲準,那若是3500也被人改了呢?事務A不知道咋辦了。3d

事務中屢次讀取結果不一致,這種現象爲不可重複讀。code

實踐

新建一張基於InnoDB引擎的表account

image.png

經過SELECT @@tx_isolation;查詢當前事務隔離級別。

image.png

Navicat開啓用於測試的查詢Session

事務A 事務B 事務C
START TRANSACTION; / /
SELECT * FROM account WHERE id = 1; / /
image.png / /
/ START TRANSACTION; /
/ UPDATE account SET balance = 3500 WHERE id = 1; /
/ COMMIT; /
/ / START TRANSACTION;
SELECT * FROM account WHERE id = 1; / SELECT * FROM account WHERE id = 1;
image.png / image.png
COMMIT; / COMMIT;

經過本示例說明,普通的SELECTSELECT * FROM account WHERE id = 1,沒有加鎖。由於若是加了鎖,InnoDB行級鎖下會拒絕寫操做。

出現問題了,雖然解決了不可重複讀的問題,可是以上帝視角來看,以3000進行運算,最終的結果仍是錯誤的。

這時候就須要鎖了。

共享鎖(讀鎖):讀時加鎖,容許其餘事務共享鎖,但不容許其餘事務獲取排它鎖。

排它鎖(寫鎖):寫時加鎖,不容許其餘事務獲取共享、排它鎖。

共享鎖、排它鎖,也成爲讀、寫鎖,鎖爲何這麼設計不用詳細描述相信你們也能理解。

DML:數據庫操做語言(不要小看概念,有人面試就掛在DML上了),也就是咱們經常使用的SELECT、INSERT、UPDATE、DELETE等操做語句。

InnoDB引擎下,默認INSERT、UPDATE、DELETE會對相關記錄加行級排它鎖,默認SELECT不加鎖。

可經過lock in share mode加共享鎖,for update加排它鎖。

共享鎖示例:

事務A 事務B
START TRANSACTION; START TRANSACTION;
SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE; /
image.png /
/ SELECT * FROM account WHERE id = 1;
/ 不加鎖查詢:image.png
/ SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE;
/ 其餘事務擁有共享鎖,本事務獲取共享鎖成功:image.png
/ SELECT * FROM account WHERE id = 1 FOR UPDATE;
/ 其餘事務擁有共享鎖,本事務獲取排它鎖失敗:image.png
/ UPDATE account SET balance = 3500 WHERE id = 1;
/ UPDATE語句獲取排它鎖,一樣失敗:image.png
COMMIT; /
/ COMMIT;

排它鎖示例:

事務A 事務B
START TRANSACTION; START TRANSACTION;
SELECT * FROM account WHERE id = 1 FOR UPDATE; /
image.png /
/ SELECT * FROM account WHERE id = 1;
/ 不加鎖查詢:image.png
/ SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE;
/ 其餘事務擁有排它鎖,本事務獲取共享鎖失敗:image.png
/ SELECT * FROM account WHERE id = 1 FOR UPDATE;
/ 其餘事務擁有排它鎖,本事務獲取排它鎖失敗:image.png
/ UPDATE account SET balance = 3500 WHERE id = 1;
/ UPDATE語句獲取排它鎖,一樣失敗:image.png
COMMIT; /
/ COMMIT;

總結

最後,提醒你們簽約慎重,警戒互聯網廠商毀約,避免被公司演一手。

image.png

相關文章
相關標籤/搜索