1、MySQL數(shù)據(jù)庫的基本結構
最上層的客戶端層負責處理鏈接處理和授權認證,安全等功能。
第二層架構是MySQL中的核心層,MySQL大多數(shù)核心功能都在這一層搞定。包括查詢解析,優(yōu)化,緩存以及MySQL所有的內置函數(shù)。所有的跨存儲引擎的功能都在這一層實現(xiàn)。
第三層是MySQL所有的存儲引擎。每一種存儲引擎都有其不同的地方,也有其優(yōu)勢和劣勢。存儲引擎除了InnoDB以外都不會去解析SQL。InnoDB因為涉及到外鍵,所以需要解析SQL。
2、MySQL的并發(fā)控制
無論何時,只要涉及到讀寫操作都會涉及到并發(fā)問題。日志,郵件,excel等等都會有這樣的問題。我之前寫過一個功能是解析日志判斷接口中日志打印的參數(shù)和傳遞的參數(shù)是否一致。最開始我沒有考慮到這個問題,寫了個線程池直接多線程給接口發(fā)請求。結果打印出來的日志全是亂七八糟的,日志格式也被改變了。
MySQL作為數(shù)據(jù)庫,肯定不能允許并發(fā)問題的發(fā)生。不可能兩個人同時對一條數(shù)據(jù)進行修改會出現(xiàn)很多種不同的結果,那樣就亂套了。
讀寫鎖:
我們常用的郵件功能,如果兩個人同時閱讀同一封郵件是完全沒有問題的。但是如果一個人在閱讀一封郵件,但是同時另外一個人修改了這封郵件,那么就會導致讀郵件的人可能會看到不同的結果。有可能是空白郵件,也有可能是沒有修改以前的郵件,還有可能亂碼等各種問題。數(shù)據(jù)庫也存在同樣的問題。
解決這類問題的最經典的方法就是加共享鎖(讀鎖)和排它鎖(寫鎖)。
共享鎖又稱讀鎖。讀一個數(shù)據(jù)的時候多少個對象同時讀取都無所謂,都可以同時讀取數(shù)據(jù),互不干擾。
排它鎖又稱寫鎖。一個寫鎖會阻塞其他的共享鎖和排它鎖。在有對象在進行寫的操作時,數(shù)據(jù)庫會將數(shù)據(jù)鎖死,不允許讀也不會允許別的用戶對其修改。
粒度鎖:
除了讀寫鎖,MySQL還有一種鎖機制叫做粒度鎖。讀寫鎖雖然可以解決讀寫矛盾問題,但是還有個很嚴重的問題就是我們應該鎖住多大的范圍?是只要有一條內容被修改我們就鎖住整個數(shù)據(jù)庫不讓讀還是鎖住整個表又或者僅僅只是鎖住被修改的那一行不讓讀?這個就涉及到粒度鎖。
我們最希望的方式是盡量精確的鎖定被修改的地方而不是鎖定所有資源,這樣可以支持更高的并發(fā)量,只要修改的數(shù)據(jù)不互相沖突即可。
但是問題是加鎖也需要消耗資源。鎖的各種操作,包括獲得鎖,檢查鎖是否被釋放,釋放鎖等等操作,都會大幅度的增加系統(tǒng)的消耗。所以采取哪一種的鎖策略,也需要在鎖的開銷和數(shù)據(jù)安全之間尋求平衡。
MySQL最重要的兩種鎖策略分別是表鎖和行級鎖。
表鎖是MySQL中開銷最小的鎖策略。當一張表中有一行被更改時,當前表就不再允許查詢和修改。一個用戶在對表進行寫操作時需要首先獲取表的排它鎖。當其獲取了排它鎖,別人就不能再對這張表進行訪問,除非他修改完該表并且釋放了鎖。
行級鎖可以最大程度的支持并發(fā)處理,但是他也是鎖消耗最大的鎖。行級鎖只會獲取需要修改的行的排它鎖,整張表的其余行依然可以進行訪問。
3、MySQL的事務
說明事務最好的方式就是轉賬。
如果A要給B轉賬200元錢。從數(shù)據(jù)庫的操作來看就是
1. 開始事務
2. A賬戶減少200元
3. B賬戶增加200元
4. 提交事務
當?shù)谌龡l執(zhí)行失敗時,事務沒有被提交,所以會直接回滾到執(zhí)行事務以前。A的賬戶不會減少200元。
事務的四大特性:原子性,一致性,隔離性,持久性
原子性:一個事務必須被視為不可分割的最小單元,整個事務必須全部提交成功或者全部提交失敗。
一致性:數(shù)據(jù)庫總是從一個一致性的狀態(tài)轉換到另外一個一致性的狀態(tài)。
隔離性:通常來說一個事務在沒有提交以前對于別的事務來說是不可見的。前面轉賬的例子如果在執(zhí)行B賬戶增加200元操作的同時另一個事務查詢了A的賬戶,A的賬戶應該還是未減少之前的狀態(tài)。
持久性:一旦事務提交,那么數(shù)據(jù)就會被永久的保存到數(shù)據(jù)庫中。這是哪怕是系統(tǒng)崩潰了,死機了,數(shù)據(jù)也不會丟失。但是這也只是理論上,否則也不會需要做備份了。
隔離性實際上比想象的要復雜的多得多。在SQL中定義了四中隔離級別,級別越低的并發(fā)能力越強,當然安全性也就越差。級別越高的并發(fā)能力越差,安全性也越強。
四大隔離級別:未提交讀,提交讀(不可重復讀),可重復讀,可串行化
未提交讀:在這個隔離級別下事務里面未提交的部分別的事務也可以看到,這又被稱之為臟讀。這個級別會導致非常多的問題,比如查詢后根據(jù)查詢到的數(shù)據(jù)修改數(shù)據(jù),就會導致數(shù)據(jù)錯誤。在性能上來說這個級別的并發(fā)性能是最好的,但是基本上不用,因為太不安全。
提交讀(不可重復讀):大多數(shù)的數(shù)據(jù)庫的默認事務隔離級別都是不可重復讀,但是MySQL不是。不可重復讀滿足了前面隔離性的簡單定義,一個事務如果沒有被提交,那么就不會被別的事務讀取結果。但是同一個事務中兩次讀取同一個數(shù)據(jù)可能獲取的結果不一樣。
可重復讀:該級別可以保證多次讀取同樣記錄的結果是一樣的,MySQL默認的就是該隔離級別,但是其無法解決幻讀的問題。
可串行化:可串行化是隔離級別的最高級別,它強制所有的事務必須串行執(zhí)行,避免了幻讀的問題,但是效率太低,一般也不會用。