1.MySQL工做流程
- 客戶端發送請求到鏈接器(受權認證處理)
- 認證經過後:請求被轉發到查詢分析器(查詢、解析、優化、緩存等等)
- 查詢緩存中若是存在數據直接返回,不然將請求再次轉發給優化器(存儲過程、觸發器、視圖等等)
- 而後將請求轉發給執行器調用存儲引擎(存儲和提取數據)
- 最終全部數據根據本地文件系統存儲在磁盤(內存)上
2.ACID特性
- 事務:訪問和更新數據庫的執行單元,包含着一個或多個SQL語句
-
標準SQL事務須要知足的特性:html
- 原子性:事務是不可分割的最小執行單元,事務中的SQL語句只會所有執行成功或所有不執行
- 一致性:事務執行先後數據保持一致性,其餘事務對同一個數據的訪問結果是一致的
- 隔離性:併發訪問數據庫時,一個用戶的事務不會被其餘事務影響,併發事務之間是隔離的
- 持久性:事務被提交以後,發生任何狀況,數據庫中數據的改變是持久的
3.事務隔離級別
3-1.髒讀/不可重複讀/幻讀
- 髒讀:A事務可以讀取其餘事務的修改(update/delete/insert)操做
- 不可重複讀:A事務可以讀取其餘事務已經提交的update/delete操做(同一條SQL查詢讀到不一樣的結果)
- 幻讀: A事務可以讀取其餘事務已經提交的insert操做(同一條SQL查詢讀到多餘結果)
3-2.標準的事務隔離級別
- 未提交讀:容許讀取其餘未提交事務的數據變動(存在髒讀/不可重複讀/幻讀問題)
- 提交讀(不可重複讀):容許讀取其餘已提交事務的數據變動(還存在不可重複讀/幻讀問題)
- 可重複讀:不容許讀取其餘已提交事務的數據變動(還存在幻讀問題)
- 可串行化:全部操做串行化,讀加讀鎖,寫加寫鎖,讀寫鎖互斥(解決幻讀問題)
3-3.實驗現象
A事務 |
B事務 |
begin; |
begin; |
update操做A記錄的時候 |
delete/update操做A記錄時會等待鎖釋放而超時;select操做A記錄時看不到更改後的數據 |
commit(釋放鎖) |
|
|
delete/update操做A記錄正常;select操做A記錄時能看到更改後的數據 |
在RC級別下:當A事務進行update操做A記錄時,爲了併發操做過程當中的衝突,會給A記錄加鎖而且若是沒有commit時,B事務delete/update操做都會超時,但解決髒讀問題;當A事務提交後,select操做存在不可重複讀問題;固然若是A事務進行insert操做,B事務很容易經過select操做讀到多餘記錄,沒有任何辦法`算法
A事務 |
B事務 |
C事務 |
begin; |
begin; |
begin; |
select操做1:查詢到A和B兩條記錄 |
|
|
|
update操做A記錄 |
|
|
commit; |
|
|
|
insert操做C記錄 |
|
|
commit; |
select操做1:同一條語句;沒有讀取到更新記錄和插入記錄 |
|
|
在INNODB存儲引擎中的現象:同一條select查詢讀不到B事務的更新刪除操做(由於讀取的記錄被加鎖,其餘事務沒法執行更新刪除操做),這樣意味着解決了不可重讀問題;也讀取不到C事務添加操做,也解決了幻讀問題(可是僅僅經過常規鎖機制是沒法阻止Insert操做的);因此在非INNODB存儲引擎中都是採用串行化去解決幻讀問題。`
- 以上是悲觀鎖的實現機制,可是爲了減小開銷,更多狀況下會依賴於樂觀鎖的MVCC(多版本併發控制)來避免以上問題
4.多版本併發控制
4-1.悲觀鎖和樂觀鎖
- 悲觀鎖:假定大機率會發生併發更新衝突,訪問和處理過程當中都會加排他鎖,整個事務過程當中鎖定數據,只有當事務提交或者回滾後才釋放鎖
- 樂觀鎖:假定大機率不會發生併發更新衝突,訪問和處理數據過程當中不加鎖,只在更新數據時再根據版本號和時間戳判斷是否有衝突(版本號不一致),有則處理,無則提交事務
4-2.MVCC
5.當前讀和快照讀
- 當前讀:即加鎖讀,讀取記錄的最新版本,會加鎖保證其餘併發事務不能修改當前記錄,直至獲取鎖的事務釋放鎖
- 快照讀:即不加鎖讀,讀取記錄的快照版本而非最新版本,經過MVCC實現
InnoDB默認的RR事務隔離級別下,不顯式加『lock in share mode』與『for update』的『select』操做都屬於快照讀,保證事務執行過程當中只有第一次讀以前提交的修改和本身的修改可見,其餘的均不可見;但咱們讀到的數據多是歷史數據,是不及時的數據,不是數據庫當前的數據!這在一些對於數據的時效特別敏感的業務中,就極可能出問題。
- 事務的隔離級別實際上都是定義了當前讀的級別,MySQL爲了減小鎖處理(包括等待其它鎖)的時間,提高併發能力,引入了快照讀的概念,使得select不用加鎖。而update、insert這些「當前讀」,就須要另外的模塊來解決了
6.鎖機制
-
InnoDB主要實現了三種行鎖算法:緩存
- Record Lock:記錄鎖,鎖定一個行記錄
- Gap Lock:間隙鎖,鎖定一個區間
- Next-key Lock:Record Lock+Gap Lock,鎖定行記錄+上下區間
- 不可重複讀狀況下:若是A事務select「當前讀」操做(會給查詢到的數據+記錄鎖),當B事務Insert新數據後,A事務再次執行相同條件的select「當前讀」操做,是可能發現多餘的數據,這就是「當前讀」的幻讀
- 可重複讀狀況下:若是A事務select「當前讀」操做(會給查詢到的記錄+記錄鎖+間隙鎖),當B事務Insert新數據後(若是在間隙空間中)會進行Waiting,此時A事務再次執行相同條件的select「當前讀」操做, 是不可能發現多餘的數據,這就解決了「當前讀」的幻讀問題。
- 間隙區間:根據不一樣的索引類型(數據結構)範圍性掃描的索引和記錄而肯定的,若是沒有Gap Lock,RR級別下是能夠隨意Insert的,從而致使「當前讀」的幻讀問題......
- 當前讀下:行鎖防止update/delete操做,GAP鎖防止Insert操做,Next-Key鎖解決了在RR級別下寫數據時的幻讀問題
- 我能夠理解爲:Gap鎖解決一致性讀問題;Next-Key鎖解決一致性寫問題嗎?
參考