很多程式員都學過MySQL,而且也會寫SQL語句。但僅僅會寫還遠遠不夠,在面試中以及在工作中,還必須要會事務和併發。 一、事務 事務是滿足 ACID 特性的操作,可以通過 Commit 提交事務,也可以使用 Rollback 進行回滾。 A(Atomicity)原子性:事務被視為不可分割的小單元,事 ...
很多程式員都學過MySQL,而且也會寫SQL語句。但僅僅會寫還遠遠不夠,在面試中以及在工作中,還必須要會事務和併發。
一、事務
事務是滿足 ACID 特性的操作,可以通過 Commit 提交事務,也可以使用 Rollback 進行回滾。 A(Atomicity)原子性:事務被視為不可分割的小單元,事務的所有操作要麼全部提交成功,要麼全部失敗回滾。 C(Consistency)一致性:資料庫在事務執行前後都保持一致性狀態。在一致性狀態下,所有事務對一個數據的讀取結果都是相同的。 I(Isolation)隔離性:事務之間的操作是相互隔離的。 D(Durability)持久性:一旦事務提交,則其所做的修改將會永遠保存到資料庫中。二、併發一致性
在併發環境下,容易造成併發一致性問題,導致隔離性被破壞。假設目前有兩個事務,分別命名為A和B,在併發環境下,容易出現以下問題。 丟失更新:A、B同時修改數據,A先,B後,A提交後B提交,B操作覆蓋了A的操作,導致A丟失更新。 讀臟數據:A修改數據,B讀取數據;隨後A撤銷操作,則B讀到臟數據。 不可重覆讀:B讀取數據,A修改數據,B再次讀取數據,發現數據和第一次讀時不一致。 幻讀:A讀取了某個範圍的數據,B在此範圍內插入一條數據;A再次讀取,結果不一樣。三、鎖
在併發環境下,為解決併發一致性問題保證事務的隔離性,可採取封鎖機制。當一個事務在進行操作時加鎖,限制另一個事務的操作。 一般而言,為保證效率,鎖的粒度不宜太大。在MySQL中,提供了行鎖和表鎖。 行鎖:事務A操作數據時,只封鎖被操作的行,事務B可以操作其他行的數據,併發程度高; 表鎖:事務A操作數據時,封鎖整個表,事務B要等A完成才能操作,併發度較低。 在讀寫方面資料庫鎖也分為讀鎖(共用鎖)和寫鎖(排他鎖)。 讀鎖:若事務A加了此鎖,A可以對數據進行讀取操作,但不能更新;其它事務也可以讀,但不能修改; 寫鎖:若事務A加了此鎖,A可以對數據進行讀和寫操作,其它事務不能讀寫,否則會阻塞。 上面所說的是悲觀鎖,MySQL中InnoDB也提供了樂觀鎖的實現——MVCC(多版本併發控制)。用通俗的方式解釋悲觀鎖和樂觀鎖大概是這樣: 悲觀鎖:認為每次操作都會修改數據,每次都在操作前上鎖; 樂觀鎖:認為每次操作都不會修改數據,不上鎖,但是會記錄一個版本號或者時間戳,用來對比。 MVCC則是樂觀鎖的實現,它在每行記錄後面都保存著兩個隱藏的列,用來存儲創建版本號和刪除版本號。四、隔離級別
若鎖的操作要用戶自己控制,會比較複雜,因此資料庫管理系統提供了事務的隔離級別,使問題簡單化。MySQL的隔離級別有四種,分別是:未提交讀、已提交讀、可重覆讀、可序列化。它們與併發一致性問題的關係如下表所示。MySQL預設隔離級別為:可重覆讀 未提交讀:事務修改數據,即使未提交,其它事務依舊可見。 已提交讀:事務修改數據提交之前,其他事務不可見。 可重覆讀:事務多次讀取數據的結果都一樣。 可序列化:解決了幻讀問題。五、存儲引擎
說到資料庫的併發問題,就要提一下MySQL的存儲引擎。MySQL的存儲引擎有很多種,最常用的還是MyISAM和InnoDB,它們的區別如下: 因此,一般在讀操作比較多的情況下,MyISAM的效率更高,因為相比於InnoDB,它維護的東西要少,比如版本號,索引數據等。 但是InnoDB支持事務,而且在併發環境下優勢顯著。至於如何選擇存儲引擎,應根據具體情況而定。總結
本文講了資料庫的事務以及併發一致性問題,並且引申出解決辦法以及MySQL的存儲引擎。這些知識,對於絕大多數從事互聯網工作的人來說,是必須要掌握的,也是在面試中經常考察的點。如果覺得對你有幫助,可以關註公眾號:Max的日常操作,或掃碼關註