1.並發控制
並發控制目的是當多個連接對數據庫進行修改時保證數據的一致性。MySQL提供兩個級別的並發控制:服務器級和存儲引擎級。
1.1 讀寫鎖
從功能上可以分為共享鎖和排他鎖,也就是我們常講的讀鎖和寫鎖。簡單描述就是:讀鎖是共享的,
或者說是互相不阻塞的。多個用戶在同一時刻可以同時讀取統一資源,而互不干擾。寫鎖則是排他的,
也就是說一個寫鎖會阻塞其他的寫鎖和讀鎖。
1.2 鎖粒度:鎖策略
從粒度上分類:
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,並發度最低。一般ddl使用。表鎖分為表共享讀鎖(共享鎖)和表獨占寫鎖(排他鎖)。
表共享讀鎖用法
LOCK TABLE ... READ;
表獨占寫鎖用法
LOCK TABLE... WRITE;
解鎖表用法
UNLOCK TABLES;
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。行級鎖分為共享鎖和排他鎖。
行共享鎖用法
SELECT ... LOCK IN SHARE MODE;
行排他鎖用法
SELECT ... FOR UPDATE;
具體鎖定哪行,后面加where條件即可。我們現在數據庫表都用的innodb,innodb支持行級鎖,如果換成myisam就不支持行級鎖。
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。
2.事務
並發事務帶來的問題
-
臟讀(Dirty Reads):A事務讀取B事務尚未提交的更改數據,並在這個數據基礎上操作。如果B事務回滾,那么A事務讀到的數據根本不是合法的,稱為臟讀。
-
不可重復讀(Non-Repeatable Reads):A事務讀取了B事務已經提交的更改(或刪除)數據。比如A事務第一次讀取數據,然后B事務更改該數據並提交,A事務再次讀取數據,兩次讀取的數據不一樣。
-
幻讀(Phantom Reads):A事務讀取了B事務已經提交的新增數據。注意和不可重復讀的區別,這里是新增,不可重復讀是更改(或刪除)。
-
更新丟失(Lost Update):第一類丟失更新:A事務撤銷時,把已提交的B事務的數據覆蓋掉。第二類丟失更新:A事務提交時,把已提交的B事務的數據覆蓋掉。
2.1事務隔離級別
未提交讀(Read uncommitted) | 可能 | 可能 | 可能 |
已提交讀(Read committed) | 不可能 | 可能 | 可能 |
可重復讀(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行化(Serializable ) | 不可能 | 不可能 | 不可能 |
隔離級別
|
臟讀(Dirty Read)
|
不可重復讀(NonRepeatable Read)
|
幻讀(Phantom Read)
|
---|
數據庫實現事務隔離的方式, 基本上可以分為兩種方式:
-
第一種: 在讀取數據前, 對其加鎖, 阻止其他事務對數據進行修改.
-
第二種: 不用加任何鎖, 通過一定機制生成一個數據請求時間點的一致性數據快照.並用這個快照來提供一定級別(語句級或事務級)的一致性讀取.從用戶的角度來看, 好像數據庫可以提供同一數據的多個版本, 因此, 這種技術叫做數據多版本並發控制(MVCC).
數據庫的事務隔離越嚴格,並發副作用越小,但付出的代價也就越大,因為事務隔離實質上就是使事務在一定程度上“串行化”進行.
3.多版本並發控制
第一點:
MVCC並不是MySql獨有的,Oracle,PostgreSQL等都在使用。
MVCC並沒有簡單地使用行鎖,而是使用“行級別鎖”(row-level locking)。
MVCC的基本原理是:
MVCC的實現,通過保存數據在某個時間點的快照來實現的。這意味着一個事務無論運行多長時間,在同一個事務里能夠看到數據一致的視圖。根據事務開始的時間不同,同時也意味着在同一個時刻不同事務看到的相同表里的數據可能是不同的。
MVCC的基本特征:
- 每行數據都存在一個版本,每次數據更新時都更新該版本。
- 修改時Copy出當前版本隨意修改,各個事務之間無干擾。
- 保存時比較版本號,如果成功(commit),則覆蓋原記錄;失敗則放棄copy(rollback)
InnoDB存儲引擎MVCC的實現策略:
InnoDB MVCC提供了兩個關鍵功能,一:寫不阻塞讀 。 二:讀一致性
在每一行數據中額外保存兩個隱藏的列:當前行創建時的版本號和刪除時的版本號(可能為空)。這里的版本號並不是實際的時間值,而是系統版本號(InnoDB engine 有一個全局的 Transaction ID)。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號,用來和查詢每行記錄的版本號進行比較。
每個事務又有自己的版本號,這樣事務內執行CRUD操作時,就通過版本號的比較來達到數據版本控制的目的。具體做法見下面的示意圖。
MVCC具體的操作如下:
SELECT:InnoDB會根據以下兩個條件檢查每行記錄:
1)InnoDB只查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,只么是在事務開始前已經存在的,要么是事務自身插入或者修改過的。
2)行的刪除版本要么未定義,要么大於當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。
INSERT:InnoDB為新插入的每一行保存當前系統版本號作為行版本號。
DELETE:InnoDB為刪除的每一行保存當前系統版本號作為行刪除標識。
UPDATE:InnoDB為插入一行新記錄,保存當前系統版本號作為行版本號,同時保存當系統的版本號為原來的行作為刪除標識。
保存這兩個額外系統版本號,使大多數操作都可以不用加鎖。這樣設計使得計數據操作很簡單,性能很好,並且也能保證只會讀取到符合標准的行。不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作,以及一些額外的維護工作。
MVCC只在REPEATABLE READ和READ COMMITED兩個隔離級別下工作,其它兩個隔離級別和MVCC不兼容。
4.常見鎖策略
鎖的策略 | 並發性 | 開銷 | 引擎 |
表 | 最低 | 最低 | MyISAM,Merge,Memory |
行 | 高 | 高 | NDB Cluster |
行和MVCC | 最高 | 最高 | InnoDB,Falcon,PBXT,solidD |