MySQL邏輯架構(gòu)
了解MySQL的架構(gòu)有助于深入理解MySQL服務(wù)器氛魁,下圖是MySQL的三層邏輯架構(gòu)圖(圖片來(lái)自于網(wǎng)絡(luò))暮顺。
第一層用于對(duì)客戶端的連接處理、安全認(rèn)證秀存、授權(quán)等捶码。每個(gè)客戶端連接都會(huì)在服務(wù)端擁有一個(gè)線程,每個(gè)連接發(fā)起的查詢都會(huì)在對(duì)應(yīng)的單獨(dú)線程中執(zhí)行或链。
第二層包含了MySQL的核心服務(wù)功能惫恼,包括查詢解析、分析澳盐、查詢緩存祈纯、內(nèi)置函數(shù)、存儲(chǔ)過(guò)程叼耙、觸發(fā)器腕窥、視圖等。當(dāng)客戶端發(fā)起請(qǐng)求時(shí)筛婉,如果是SELECT操作簇爆,MySQL會(huì)先檢查是否命中查詢緩存,命中則直接返回查詢緩存中的數(shù)據(jù)爽撒;否則入蛆,MySQL會(huì)解析查詢并創(chuàng)建對(duì)應(yīng)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(解析樹),執(zhí)行各種優(yōu)化硕勿,然后執(zhí)行哨毁。
第三層包含了存儲(chǔ)引擎,存儲(chǔ)引擎負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和提取源武。MySQL中有很多種不同類型的存儲(chǔ)引擎扼褪,每個(gè)存儲(chǔ)引擎各不相同,MySQL服務(wù)器通過(guò)API與存儲(chǔ)引擎通信粱栖,屏蔽了各種存儲(chǔ)引擎之間的差異迎捺。
MySQL中的鎖
MySQL在處理并發(fā)讀和寫的時(shí)候,分別使用共享鎖(讀鎖)和排它鎖(寫鎖)查排。
對(duì)共享資源高并發(fā)操作凳枝,在加鎖的時(shí)候,最好能只鎖定所需要的數(shù)據(jù),控制鎖的粒度岖瑰、提高并發(fā)能力叛买。MySQL提供了兩種最重要的鎖策略,表級(jí)鎖和行級(jí)鎖蹋订。
表級(jí)鎖,即鎖定整張表。在對(duì)表進(jìn)行插入动漾、更新、刪除操作時(shí)荠锭,需要先獲得寫鎖旱眯,鎖定整張表,其它讀寫操作將會(huì)被阻塞证九。讀鎖之間是不會(huì)阻塞的删豺。需要注意的是alter table操作會(huì)使用表級(jí)鎖,所以對(duì)數(shù)據(jù)量很大的表進(jìn)行alter table操作時(shí)愧怜,需要謹(jǐn)慎呀页。
行級(jí)鎖,即只鎖定數(shù)據(jù)所在的行蓬蝶,行級(jí)鎖只在存儲(chǔ)引擎層實(shí)現(xiàn)渴逻。行級(jí)鎖可以很好的支持并發(fā)處理疾党,但是也會(huì)導(dǎo)致大量的資源開銷音诫。
事務(wù)特性
四大特性(ACID):原子性(Atomicity)惨奕、一致性(Consistency)竭钝、隔離性(Isolation)香罐、持久性(Durability)卧波。
原子性:一個(gè)事務(wù)中的所有操作,要么全部成功執(zhí)行庇茫,要么全部失敗回滾港粱;
一致性:事務(wù)執(zhí)行結(jié)果使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài);
隔離性:事務(wù)操作提交之前,操作結(jié)果對(duì)其它事務(wù)不可見查坪;
持久性:事務(wù)提交后寸宏,所有的修改操作會(huì)永久保存到數(shù)據(jù)庫(kù)中。
事務(wù)隔離級(jí)別
SQL標(biāo)準(zhǔn)中定義了四種隔離級(jí)別偿曙,分別是Read Uncommitted氮凝、Read Committed、Repeatable Read望忆、Serializable罩阵。
Read Uncommitted:該隔離級(jí)別下,事務(wù)中未提交的數(shù)據(jù)對(duì)其它事務(wù)是可見的启摄,即其它事務(wù)可以讀取到未提交事務(wù)的數(shù)據(jù)稿壁,出現(xiàn)臟讀。
Read Committed:該隔離級(jí)別下鞋仍,事務(wù)只能讀取到已提交事務(wù)所改變的數(shù)據(jù)常摧,解決了臟讀的問題,但是會(huì)出現(xiàn)不可重復(fù)讀威创,即在一個(gè)事務(wù)前后兩次讀取某數(shù)據(jù)的中間時(shí)刻落午,有其它事務(wù)修改了該數(shù)據(jù),導(dǎo)致兩次讀取的數(shù)據(jù)不一致肚豺。
Repeatable Read:該隔離級(jí)別是MySQL數(shù)據(jù)庫(kù)的默認(rèn)事務(wù)隔離級(jí)別溃斋,它解決了不可重復(fù)讀的問題,但是會(huì)出現(xiàn)幻讀吸申,即事務(wù)在讀取某范圍內(nèi)的數(shù)據(jù)時(shí)梗劫,其它事務(wù)在該范圍內(nèi)插入了新紀(jì)錄,導(dǎo)致之前的事務(wù)再次讀取會(huì)不一致截碴。
Serializable:最高的隔離級(jí)別梳侨,該隔離級(jí)別下,通過(guò)強(qiáng)制事務(wù)串行執(zhí)行日丹、在讀取的每一行數(shù)據(jù)上加鎖走哺,來(lái)避免出現(xiàn)幻讀的問題。因?yàn)樽x取的數(shù)據(jù)每行上都會(huì)加鎖哲虾,可能會(huì)導(dǎo)致大量的超時(shí)和鎖競(jìng)爭(zhēng)問題丙躏,所以一般不使用該級(jí)別,除非是數(shù)據(jù)一致性要求特別高的情況束凑。
下面通過(guò)一張圖清晰的展示各隔離級(jí)別晒旅。
MySQL可以通過(guò)執(zhí)行SET TRANSACTION ISOLATION LEVEL命令來(lái)設(shè)置隔離級(jí)別,新設(shè)置的隔離級(jí)別將在下一個(gè)事務(wù)開始的時(shí)候生效汪诉。
MySQL中的死鎖
死鎖是指多個(gè)事務(wù)在同一資源上相互占用废恋,并請(qǐng)求鎖定對(duì)方所占用的資源,從而導(dǎo)致的惡性循環(huán)現(xiàn)象。
數(shù)據(jù)庫(kù)系統(tǒng)為了解決這個(gè)問題鱼鼓,實(shí)現(xiàn)了死鎖檢測(cè)和死鎖超時(shí)機(jī)制孝常。在MySQL的InnoDB存儲(chǔ)引擎中,解決死鎖的方法是將持有最少行級(jí)排它鎖的事務(wù)進(jìn)行回滾蚓哩。
MySQL事務(wù)日志
事務(wù)日志构灸,即一種特殊的操作記錄日志。
存儲(chǔ)引擎在修改表數(shù)據(jù)的時(shí)候岸梨,只修改內(nèi)存中的拷貝喜颁,然后將修改行為記錄保存到硬盤上的事務(wù)日志中,對(duì)事務(wù)日志的保存操作采用追加的方式曹阔,保存操作是順序IO半开,相對(duì)于存儲(chǔ)引擎直接將數(shù)據(jù)持久化到硬盤的隨機(jī)IO高效的多。事務(wù)日志保存后赃份,內(nèi)存中被修改的數(shù)據(jù)在后臺(tái)可以慢慢的持久化到硬盤寂拆。如果事務(wù)日志保存成功了,而內(nèi)存中被修改的數(shù)據(jù)沒有成功的寫入硬盤抓韩,發(fā)生了系統(tǒng)崩潰纠永,存儲(chǔ)引擎會(huì)在重啟時(shí)自動(dòng)恢復(fù)這部分?jǐn)?shù)據(jù)。
MySQL中的事務(wù)
MySQL中的事務(wù)是在存儲(chǔ)引擎中實(shí)現(xiàn)的谒拴,所以上層的服務(wù)是不會(huì)管理事務(wù)的尝江。默認(rèn)情況下,MySQL自身提供了兩種事務(wù)型的存儲(chǔ)引擎英上,分別是InnnoDB和NDB Cluster炭序。
在默認(rèn)情況下,MySQL事務(wù)采用自動(dòng)提交模式苍日,即如果沒有顯示的開啟一個(gè)事務(wù)惭聂,那么每一次的查詢都將被當(dāng)做一個(gè)事務(wù)執(zhí)行自動(dòng)提交。當(dāng)然相恃,也可以通過(guò)設(shè)置來(lái)改變這種自動(dòng)提交的模式辜纲。如果想開啟自動(dòng)提交,可以通過(guò)命令SET AUTOCOMMIT = 1或SET AUTOCOMMIT = ON來(lái)設(shè)置豆茫;關(guān)閉自動(dòng)提交模式侨歉,可以通過(guò)命令SET AUTOCOMMIT = 0或SET AUTOCOMMIT = OFF來(lái)設(shè)置屋摇。
InnoDB存儲(chǔ)引擎采用的是兩階段鎖定協(xié)議揩魂,在事務(wù)執(zhí)行的過(guò)程中,InnoDB會(huì)根據(jù)隔離級(jí)別在需要加鎖的時(shí)候自定加鎖炮温,鎖只有在事務(wù)提交或回滾的時(shí)候才會(huì)釋放火脉。當(dāng)然,也可以顯示的加鎖,如使用SELECT FOR UPDATE倦挂,也可以使用服務(wù)層實(shí)現(xiàn)的LOCK TABLES和UNLOCK TABLES畸颅。
多版本并發(fā)控制(MVCC)
基于對(duì)并發(fā)性能的考慮,MySQL的大多數(shù)事務(wù)型存儲(chǔ)引擎都實(shí)現(xiàn)了多版本并發(fā)控制方援,可以簡(jiǎn)單的認(rèn)為MVCC是行級(jí)鎖的一個(gè)變種没炒,但是它在很多情況下避免了加鎖操作,降低了開銷犯戏。
InnoDB的MVCC是通過(guò)在每行記錄后添加兩個(gè)隱藏列來(lái)實(shí)現(xiàn)的送火,一個(gè)列用于保存行的創(chuàng)建時(shí)間,一個(gè)列用于保存行的過(guò)期時(shí)間先匪,這兩個(gè)時(shí)間在實(shí)際存儲(chǔ)的時(shí)候种吸,存儲(chǔ)的是系統(tǒng)版本號(hào)。每開始一個(gè)新事務(wù)呀非,系統(tǒng)版本號(hào)都將遞增坚俗。需要注意的是MVCC只能在Read Committed和Repeatable Read隔離級(jí)別下正常工作。
MySQL存儲(chǔ)引擎
MySQL自身和第三方提供了多種存儲(chǔ)引擎岸裙,每種存儲(chǔ)引擎優(yōu)勢(shì)各不相同猖败,可以根據(jù)實(shí)際業(yè)務(wù)需要來(lái)選擇對(duì)應(yīng)的存儲(chǔ)引擎。
InnoDB是MySQL的默認(rèn)事務(wù)型存儲(chǔ)引擎降允,主要用來(lái)處理大量的短期型事務(wù)辙浑。它采用MVCC來(lái)支持高并發(fā),默認(rèn)的事務(wù)隔離級(jí)別是Repeatable Read拟糕,并通過(guò)間隙鎖策略防止幻讀的出現(xiàn)判呕。InnoDB表是基于聚簇索引建立的,而聚簇索引可以提高對(duì)主鍵查詢的性能送滞,但是它的二級(jí)索引(非主鍵索引)中必須包含主鍵侠草,如果主鍵列很大,并且有很多個(gè)二級(jí)索引犁嗅,那么這些索引將會(huì)占用很大的空間和資源边涕,所以在創(chuàng)建主鍵的時(shí)候盡量的小。
在MySQL5.1及之前的版本中褂微,MyISAM是默認(rèn)的存儲(chǔ)引擎功蜓,它提供了全文索引、壓縮宠蚂、空間函數(shù)等功能式撼,但是它不支持事務(wù)和行級(jí)鎖,并且崩潰后無(wú)法安全恢復(fù)求厕,而InnoDB引擎是可以自動(dòng)崩潰恢復(fù)的著隆。MyISAM在并發(fā)的情況下扰楼,對(duì)整張表加鎖,讀操作會(huì)對(duì)需要讀的所有表加共享鎖美浦,寫入時(shí)對(duì)表加排它鎖弦赖。