MySQL邏輯架構
了解MySQL的架構有助于深入理解MySQL服務器,下圖是MySQL的三層邏輯架構圖(圖片來自于網(wǎng)絡)。
第一層用于對客戶端的連接處理、安全認證、授權等。每個客戶端連接都會在服務端擁有一個線程,每個連接發(fā)起的查詢都會在對應的單獨線程中執(zhí)行。
第二層包含了MySQL的核心服務功能,包括查詢解析、分析、查詢緩存、內置函數(shù)、存儲過程、觸發(fā)器、視圖等。當客戶端發(fā)起請求時,如果是SELECT操作,MySQL會先檢查是否命中查詢緩存,命中則直接返回查詢緩存中的數(shù)據(jù);否則,MySQL會解析查詢并創(chuàng)建對應的內部數(shù)據(jù)結構(解析樹),執(zhí)行各種優(yōu)化,然后執(zhí)行。
第三層包含了存儲引擎,存儲引擎負責數(shù)據(jù)的存儲和提取。MySQL中有很多種不同類型的存儲引擎,每個存儲引擎各不相同,MySQL服務器通過API與存儲引擎通信,屏蔽了各種存儲引擎之間的差異。
MySQL中的鎖
MySQL在處理并發(fā)讀和寫的時候,分別使用共享鎖(讀鎖)和排它鎖(寫鎖)。
對共享資源高并發(fā)操作,在加鎖的時候,最好能只鎖定所需要的數(shù)據(jù),控制鎖的粒度、提高并發(fā)能力。MySQL提供了兩種最重要的鎖策略,表級鎖和行級鎖。
表級鎖,即鎖定整張表。在對表進行插入、更新、刪除操作時,需要先獲得寫鎖,鎖定整張表,其它讀寫操作將會被阻塞。讀鎖之間是不會阻塞的。需要注意的是alter table操作會使用表級鎖,所以對數(shù)據(jù)量很大的表進行alter table操作時,需要謹慎。
行級鎖,即只鎖定數(shù)據(jù)所在的行,行級鎖只在存儲引擎層實現(xiàn)。行級鎖可以很好的支持并發(fā)處理,但是也會導致大量的資源開銷。
事務特性
四大特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。
原子性:一個事務中的所有操作,要么全部成功執(zhí)行,要么全部失敗回滾;
一致性:事務執(zhí)行結果使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài);
隔離性:事務操作提交之前,操作結果對其它事務不可見;
持久性:事務提交后,所有的修改操作會永久保存到數(shù)據(jù)庫中。
事務隔離級別
SQL標準中定義了四種隔離級別,分別是Read Uncommitted、Read Committed、Repeatable Read、Serializable。
Read Uncommitted:該隔離級別下,事務中未提交的數(shù)據(jù)對其它事務是可見的,即其它事務可以讀取到未提交事務的數(shù)據(jù),出現(xiàn)臟讀。
Read Committed:該隔離級別下,事務只能讀取到已提交事務所改變的數(shù)據(jù),解決了臟讀的問題,但是會出現(xiàn)不可重復讀,即在一個事務前后兩次讀取某數(shù)據(jù)的中間時刻,有其它事務修改了該數(shù)據(jù),導致兩次讀取的數(shù)據(jù)不一致。
Repeatable Read:該隔離級別是MySQL數(shù)據(jù)庫的默認事務隔離級別,它解決了不可重復讀的問題,但是會出現(xiàn)幻讀,即事務在讀取某范圍內的數(shù)據(jù)時,其它事務在該范圍內插入了新紀錄,導致之前的事務再次讀取會不一致。
Serializable:最高的隔離級別,該隔離級別下,通過強制事務串行執(zhí)行、在讀取的每一行數(shù)據(jù)上加鎖,來避免出現(xiàn)幻讀的問題。因為讀取的數(shù)據(jù)每行上都會加鎖,可能會導致大量的超時和鎖競爭問題,所以一般不使用該級別,除非是數(shù)據(jù)一致性要求特別高的情況。
MySQL可以通過執(zhí)行SET TRANSACTION ISOLATION LEVEL命令來設置隔離級別,新設置的隔離級別將在下一個事務開始的時候生效。
MySQL中的死鎖
死鎖是指多個事務在同一資源上相互占用,并請求鎖定對方所占用的資源,從而導致的惡性循環(huán)現(xiàn)象。
數(shù)據(jù)庫系統(tǒng)為了解決這個問題,實現(xiàn)了死鎖檢測和死鎖超時機制。在MySQL的InnoDB存儲引擎中,解決死鎖的方法是將持有最少行級排它鎖的事務進行回滾。
MySQL事務日志
事務日志,即一種特殊的操作記錄日志。
存儲引擎在修改表數(shù)據(jù)的時候,只修改內存中的拷貝,然后將修改行為記錄保存到硬盤上的事務日志中,對事務日志的保存操作采用追加的方式,保存操作是順序IO,相對于存儲引擎直接將數(shù)據(jù)持久化到硬盤的隨機IO高效的多。事務日志保存后,內存中被修改的數(shù)據(jù)在后臺可以慢慢的持久化到硬盤。如果事務日志保存成功了,而內存中被修改的數(shù)據(jù)沒有成功的寫入硬盤,發(fā)生了系統(tǒng)崩潰,存儲引擎會在重啟時自動恢復這部分數(shù)據(jù)。
MySQL中的事務
MySQL中的事務是在存儲引擎中實現(xiàn)的,所以上層的服務是不會管理事務的。默認情況下,MySQL自身提供了兩種事務型的存儲引擎,分別是InnnoDB和NDB Cluster。
在默認情況下,MySQL事務采用自動提交模式,即如果沒有顯示的開啟一個事務,那么每一次的查詢都將被當做一個事務執(zhí)行自動提交。當然,也可以通過設置來改變這種自動提交的模式。如果想開啟自動提交,可以通過命令SET AUTOCOMMIT = 1或SET AUTOCOMMIT = ON來設置;關閉自動提交模式,可以通過命令SET AUTOCOMMIT = 0或SET AUTOCOMMIT = OFF來設置。
InnoDB存儲引擎采用的是兩階段鎖定協(xié)議,在事務執(zhí)行的過程中,InnoDB會根據(jù)隔離級別在需要加鎖的時候自定加鎖,鎖只有在事務提交或回滾的時候才會釋放。當然,也可以顯示的加鎖,如使用SELECT FOR UPDATE,也可以使用服務層實現(xiàn)的LOCK TABLES和UNLOCK TABLES。
多版本并發(fā)控制(MVCC)
基于對并發(fā)性能的考慮,MySQL的大多數(shù)事務型存儲引擎都實現(xiàn)了多版本并發(fā)控制,可以簡單的認為MVCC是行級鎖的一個變種,但是它在很多情況下避免了加鎖操作,降低了開銷。
InnoDB的MVCC是通過在每行記錄后添加兩個隱藏列來實現(xiàn)的,一個列用于保存行的創(chuàng)建時間,一個列用于保存行的過期時間,這兩個時間在實際存儲的時候,存儲的是系統(tǒng)版本號。每開始一個新事務,系統(tǒng)版本號都將遞增。需要注意的是MVCC只能在Read Committed和Repeatable Read隔離級別下正常工作。
MySQL存儲引擎
MySQL自身和第三方提供了多種存儲引擎,每種存儲引擎優(yōu)勢各不相同,可以根據(jù)實際業(yè)務需要來選擇對應的存儲引擎。
InnoDB是MySQL的默認事務型存儲引擎,主要用來處理大量的短期型事務。它采用MVCC來支持高并發(fā),默認的事務隔離級別是Repeatable Read,并通過間隙鎖策略防止幻讀的出現(xiàn)。InnoDB表是基于聚簇索引建立的,而聚簇索引可以提高對主鍵查詢的性能,但是它的二級索引(非主鍵索引)中必須包含主鍵,如果主鍵列很大,并且有很多個二級索引,那么這些索引將會占用很大的空間和資源,所以在創(chuàng)建主鍵的時候盡量的小。
在MySQL5.1及之前的版本中,MyISAM是默認的存儲引擎,它提供了全文索引、壓縮、空間函數(shù)等功能,但是它不支持事務和行級鎖,并且崩潰后無法安全恢復,而InnoDB引擎是可以自動崩潰恢復的。MyISAM在并發(fā)的情況下,對整張表加鎖,讀操作會對需要讀的所有表加共享鎖,寫入時對表加排它鎖。
原文地址:
https://wind7rui.github.io/2017/10/29/MySQL%E6%9E%B6%E6%9E%84%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

