MySQL-技術專題-事務和併發一致性問題

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"什麼是事務"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 事務指的是滿足 "},{"type":"text","marks":[{"type":"strong"}],"text":"ACID "},{"type":"text","text":"特性的一組操作,通過 "},{"type":"text","marks":[{"type":"strong"}],"text":"Commit "},{"type":"text","text":"提交一個事務,也使用 "},{"type":"text","marks":[{"type":"strong"}],"text":"Rollback "},{"type":"text","text":"進行回滾。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 事務是併發控制的單位,一系列操作組成的工作單元,該工作單元內的操作是不可分割的,也就是事務具有原子性,一個事務中的一系列的操作要麼全部成功,要麼一個都不做,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 事務的結束有兩種,當事務中的所有步驟全部成功執行時,事務提交。如果其中一個步驟失敗,將發生回滾操作,撤消撤消之前到事務開始時的所以操作。 "}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"事務的ACID"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1. 原子性(Atomicity)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 事務被視爲不可分割的最小單元,事務的所有操作要麼全部提交成功,要麼全部失敗回滾。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 回滾可以用回滾日誌來實現,回滾日誌記錄着事務所執行的修改操作,在回滾時反向執行這些修改操作即可。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2. 一致性(Consistency)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據庫在事務執行前後都保持一致性狀態。在一致性狀態下,所有事務對一個數據的讀取結果都是相同的。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3. 隔離性(Isolation)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個事務所做的修改在最終提交以前,對其它事務是不可見的。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4. 持久性(Durability)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 一旦事務提交,則其所做的修改將會永遠保存到數據庫中。即使系統發生崩潰,事務執行的結果也不能丟失。使用重做日誌來保證持久性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 事務的 ACID 特性概念簡單,但不是很好理解,主要是因爲這幾個特性不是一種平級關係:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"1、只有滿足一致性,事務的執行結果纔是正確的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"2、在無併發的情況下,事務串行執行,隔離性一定能夠滿足。此時只要能滿足原子性,就能滿足一致性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"3、在併發的情況下,多個事務並行執行,事務不僅要滿足原子性,還需要滿足隔離性,才能滿足一致性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"4、事務滿足持久化是爲了能應對數據庫崩潰的情況。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"併發一致性問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 在併發環境下,"},{"type":"text","marks":[{"type":"strong"}],"text":"事務的隔離性"},{"type":"text","text":"很難保證,因此會出現很多併發一致性問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" T1是指事務1,T2是指事務2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 丟失修改:兩個事務同時操作相同數據,後提交的事務會覆蓋先提交的事務處理結果,通過樂觀鎖就可以解決,悲觀鎖也可以。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 例如:T1和T2兩個事務都對一個數據進行修改,T 1 先修改,T 2 隨後修改,T 2 的修改覆蓋了 T 1 的修改。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 讀髒數據:事務A讀取到了事務B已經修改但尚未提交的數據,如果事務B回滾,A讀取的數據無效,不符合一致性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 例如:T1修改一個數據,T 2 隨後讀取這個數據。如果 T 1 撤銷了這次修改,那麼 T 2 讀取的數據是髒數據。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 不可重複讀:事務A讀取到了事務B已經提交的修改數據,不符合隔離性,也不符合一致性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如:T 2 讀取一個數據,T 1 對該數據做了修改。如果 T 2 再次讀取這個數據,此時讀取的結果和第一次讀取的結果不同。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 幻讀:事務A讀取到了事務B提交的新增數據,不符合隔離性,也不符合一致性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如:T 1 讀取某個範圍的數據,T 2 在這個範圍內插入新的數據,T 1 再次讀取這個範圍的數據,此時讀取的結果和和第一次讀取的結果不同。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 產生併發性一致性問題,那肯定是不符合一致性,只有滿足了一致性,事務的執行結果纔是正確的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"產生併發不一致性問題主要原因是"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"破壞了事務的隔離性,解決方法是通過併發控制來保證隔離性"},{"type":"text","marks":[{"type":"strong"}],"text":"。"},{"type":"text","text":"併發控制可以通過封鎖來實現,但是封鎖操作需要用戶自己控制,相當複雜。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 數據庫管理系統提供了事務的隔離級別,讓用戶以一種更輕鬆的方式處理併發一致性問題。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"MySQL的共享鎖和排它鎖"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1、共享鎖"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 共享鎖也叫讀鎖(Shared Lock),簡稱S鎖,原理:一個事務獲取了一個數據行的共享鎖,其他事務能獲得該行對應的共享鎖,但不能獲得排他鎖,即一個事務在讀取一個數據行的時候,其他事務也可以讀,但不能對該數據行進行增刪改。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2、排他鎖"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 排他鎖也叫寫鎖(Exclusive Lock),簡稱x鎖,原理:一個事務獲取了一個數據行的排他鎖,其他事務就不能再獲取該行的其他鎖(排他鎖或者共享鎖),即一個事務在讀取一個數據行的時候,其他事務不能對該數據行進行增刪改查。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"隔離級別"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d6/d610702e5947669d49a39f4a167f24f9.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1、讀未提交(READ_UNCOMMITED)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)事務對當前被讀取的數據不加鎖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)事務在更新某數據的瞬間(發生更新的瞬間),必須先對其加行級共享鎖,直到事務結束才釋放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"理解:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 1、事務B更改了某個數據,此時加的是行級共享鎖,事務A還是可以讀取到這個更改了的數據,如果事務B回滾,事務A讀取到的數據發生變化,造成髒讀。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 2、事務A讀取某個數據,事務B對其修改並提交,事務A再次讀取,得到的是不一樣的結果,造成不可重複讀"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 3、同理會造成幻讀,因爲增加了新的一行數據,那行數據沒有添加排它鎖"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2、讀已提交(READ_COMMITED)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" (1)事務對當前被讀取的數據加行級共享鎖(當讀到時才加鎖),一旦讀完,立即釋放行級共享鎖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" (2)事務更新某數據的瞬間(就是發生更新的瞬間),必須對其加行級排他鎖,直到事務結束才釋放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 理解:由(2)可以知道,事務B修改某個數據的時候,對當前行添加了行級排它鎖,於是事務A直到事務結束才能訪問這個數據,如果這個數據發生了回滾,也不會造成髒讀,但如果數據沒有回滾,兩次查到的數據不一致,造成不可重複讀,也會造成幻讀,因爲只是對修改的行加了排它鎖,其他行沒有添加。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3、可重複讀(REPEATABLE_READ)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" (1)事務讀取某數據的瞬間(就是開始讀取的瞬間),必須先對其加行級共享鎖,事務結束才釋放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" (2)事務更新某數據的瞬間(就是發生更新的瞬間),必須先對其加行級排他鎖,事務結束才釋放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 理解:事務A讀取某個數據的時候,添加了行級共享鎖,只能讀不能改,因此不會造成修改,也就不存在髒讀和不可重複讀,但是幻讀還是可能存在的,因爲只是當前行添加了排它鎖,其他行沒有鎖。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4、可串行化(SERIALIZABLE)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)事務在讀取數據時,必須先對其加表級共享鎖 ,直到事務結束才釋放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)事務在更新數據時,必須先對其加表級排他鎖,直到事務結束才釋放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"理解:整個表都添加了鎖,也就不存在增刪改了,但是這樣會大大降低數據庫的性能,所以不建議使用這個隔離級別。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"不可重複讀和幻讀的區別"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 不可重複讀重點在於 "},{"type":"text","marks":[{"type":"strong"}],"text":"update"},{"type":"text","text":" 和 "},{"type":"text","marks":[{"type":"strong"}],"text":"delete"},{"type":"text","text":" ,而幻讀的重點在於"},{"type":"text","marks":[{"type":"strong"}],"text":" insert"},{"type":"text","text":"。如果使用鎖機制來實現這兩種隔離級別,在可重複讀中,該 sql 第一次讀取到數據後,就將這些數據加鎖,其它事務無法修改這些數據,就可以實現可重複讀了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 但這種方法卻無法鎖住 insert 的數據,所以當事務 A 先前讀取了數據,或者修改了全部數據,事務 B 還是可以insert數據提交,這時事務 A 就會發現莫名其妙多了一條之前沒有的數據,這就是幻讀,不能通過行鎖來避免。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 需要 Serializable 隔離級別,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼做可以有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的降低數據庫的併發能力。所以說不可重複讀和幻讀最大的區別,就在於如何通過鎖機制來解決他們產生的問題。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"MySQL默認的隔離級別是:可重複讀(REPEATABLE_READ)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章