以前在面試準備期間寫過相關的筆記,但時間倉促,未進行詳述,對你們參考意義不大。面試
在MySQL
數據庫面試/開發中,事務一直是重中之重,這些知識在以前面試的時候學過,到如今也記得不太清楚了,本文帶領你們一塊兒來回顧MySQL
的事務知識。數據庫
事務一般併發執行,爲了不事務併發形成的一系列問題,數據庫設計四大事務隔離級別:併發
MySQL
默認的事務隔離級別是REPEATABLE-READ
,Oracle
默認的
事務隔離級別是READ-COMMITTED
。數據庫設計
在MySQL
的衆多引擎中,只有InnoDB
引擎支持事務與外鍵,而另外一經常使用的MyISAM
引擎雖不支持事務、外鍵,但訪問速度快。測試
下圖來自:《深刻淺出MySQL
數據庫開發優化與管理維護》優化
咱們聊聊最難理解的REPEATABLE-READ
級別。spa
在READ-COMMITED
隔離級別下,會出現如下問題:設計
事務A | 事務B |
---|---|
開啓事務 | 開啓事務 |
查詢帳戶餘額爲3000元 | / |
/ | 更新帳戶餘額爲3500元 |
/ | 提交事務 |
使用相同的條件去查詢帳戶餘額,發現餘額變爲了3500元 | / |
提交事務 | / |
事務A
就很蒙圈,兩次查詢結果不同,我以哪一個爲準呢?要是以3500
爲準,那若是3500
也被人改了呢?事務A
不知道咋辦了。3d
事務中屢次讀取結果不一致,這種現象爲不可重複讀。code
新建一張基於InnoDB
引擎的表account
。
經過SELECT @@tx_isolation;
查詢當前事務隔離級別。
去Navicat
開啓用於測試的查詢Session
:
事務A | 事務B | 事務C |
---|---|---|
START TRANSACTION; | / | / |
SELECT * FROM account WHERE id = 1; | / | / |
![]() |
/ | / |
/ | 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; |
![]() |
/ | ![]() |
COMMIT; | / | COMMIT; |
經過本示例說明,普通的SELECT
:SELECT * 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; | / |
![]() |
/ |
/ | SELECT * FROM account WHERE id = 1; |
/ | 不加鎖查詢:![]() |
/ | SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE; |
/ | 其餘事務擁有共享鎖,本事務獲取共享鎖成功:![]() |
/ | SELECT * FROM account WHERE id = 1 FOR UPDATE; |
/ | 其餘事務擁有共享鎖,本事務獲取排它鎖失敗:![]() |
/ | UPDATE account SET balance = 3500 WHERE id = 1; |
/ | UPDATE語句獲取排它鎖,一樣失敗:![]() |
COMMIT; | / |
/ | COMMIT; |
排它鎖示例:
事務A | 事務B |
---|---|
START TRANSACTION; | START TRANSACTION; |
SELECT * FROM account WHERE id = 1 FOR UPDATE; | / |
![]() |
/ |
/ | SELECT * FROM account WHERE id = 1; |
/ | 不加鎖查詢:![]() |
/ | SELECT * FROM account WHERE id = 1 LOCK IN SHARE MODE; |
/ | 其餘事務擁有排它鎖,本事務獲取共享鎖失敗:![]() |
/ | SELECT * FROM account WHERE id = 1 FOR UPDATE; |
/ | 其餘事務擁有排它鎖,本事務獲取排它鎖失敗:![]() |
/ | UPDATE account SET balance = 3500 WHERE id = 1; |
/ | UPDATE語句獲取排它鎖,一樣失敗:![]() |
COMMIT; | / |
/ | COMMIT; |
最後,提醒你們簽約慎重,警戒互聯網廠商毀約,避免被公司演一手。