1. 程式人生 > >事務學習總結(1)——事務的基本概念

事務學習總結(1)——事務的基本概念

一:什麼是事務?

    對資料庫讀寫一系列操作的合集。

    具有"ACID"的特性,即原子性、一致性、隔離性、永續性。

    核心點是鎖與併發。

二:主要用在哪些場景?解決了什麼問題?

    主要用於資料層面,通過約定事務的規則來保證資料的可靠性、有效性。
    主要解決了髒讀、不可重複讀、幻讀的問題。

三:ACID?

     原子性(Atomicity):對資料庫一系列操作,具有不可分割的特徵,要不一起執行要不都不執行(回滾)。就像我們在化學課裡學到的原子,原子是構成物質的最小單位。

    一致性(Consistency):執行完資料庫操作,資料不會被破壞。比如銀行實時轉賬,A向B轉100元,使用者看到結果是轉賬成功(A少了100元,B多了100元),轉賬失敗(A、B的餘額都沒有變化)。但是不會看到說中間狀態(A少了100元,B沒有變化)。

    隔離性(Isolation):多條事務併發操作時,一個事務的操作不應影響其他事務的執行。約定了4個隔離性級別,讀未提交、讀已提交、可重複讀、序列化,從前往後級別越來越高、併發性越來越差、安全性越來越高。

   永續性(Durability):已被提交的事務對資料庫的修改應該永久儲存在資料庫中。

資料庫發生故障時,確保提交的事務不丟失,未提交的事務可以正常進行回滾。通過記錄資料庫操作日誌來保證。

四、隔離性詳細說明:

   1、讀未提交:事務A讀取到事務B未提交的資料。存在的問題:髒讀、不可重複讀、幻讀。

   2、讀已提交:事務A讀取到事務B已提交的資料。例如:事務A在兩次讀操作之間,事務B對資料進行了修改並完成了提交,事務A兩次讀取的結果不一致。解決的問題:髒讀。存在的問題:不可重複讀、幻讀。

   3、可重複讀:事務A多次讀取的資料值是一樣的。其中可重複讀是通過mvcc來實現的又叫快照讀,在事務中的讀操作通過對當前的資料庫中記錄一個版本,以後的讀操作只會讀取記錄的版本,因此相當於對資料庫的資料建立了一個快照資料,因此叫做快照讀,其不用對資料庫中的資料進行加鎖又叫做樂觀鎖。解決的問題:髒讀、不可重複讀。存在的問題:幻讀。

   4、可序列化:將所有的事務排隊,利用排他鎖的方式,將事務鎖住,單位時間內,只有一個事務進來。解決的問題:髒讀、不可重複讀、幻讀。

 

五、三類資料讀問題:

   1、髒讀:事務A讀取到事務B未提交的資料。在“讀未提交”級別會出現,“讀已提交”及以上級別解決了這個問題。

   2、不可重複讀:事務A在兩次讀操作之間,事務B對資料進行了修改並完成了提交,事務A兩次讀取的結果不一致。在“讀已提交”及以下級別會出現,“可重複讀”級別解決了這個問題。

   3、幻讀:A事務讀取B事務提交的新增資料會引發幻讀問題。幻讀一般發生在計算統計資料的事務中,例如銀行系統在同一個事務中兩次統計存款賬戶的總金額,在兩次統計中,剛好新增了一個存款賬戶,存入了100,這時候兩次統計的總金額不一致。在“可重複讀”及以下級別會出現,“可序列化”級別解決了這個問題。

    不可重複讀和幻讀的區別:

             不可重複讀已經提交的事務的更改資料(修改或刪除)

             幻讀:指讀到了其他已經提交事務的新增資料

             在可重複讀的隔離級別,只會在已經存在的行加上行鎖,而不會增加表鎖。因為針對新增的資料,行鎖是無效的,所以會產生幻讀。

 

六、兩類資料更新問題:

    1、第一類丟失更新。A事務撤銷時,把已經提交的B事務的更新資料覆蓋了。在當前的四種任意隔離級別中,都不會發生該情況。

    2、第二類丟失更新。B事務覆蓋A事務已經提交的資料,造成A事務所做操作丟失。在“讀未提交”、“讀已提交”級別會發生。

 

七、總結:

 

八、MVCC(多版本控制模型):

    “讀未提交”級別產生的髒讀,基本上是不被允許的。“可序列化”級別的效能太差,基本也不會被使用。那麼主流就在“讀已提交”、“可重複讀”兩個級別進行選擇,並進行相應的效能優化。“讀已提交”級別會產生“第二類丟失更新”問題(B事務覆蓋A事務已經提交的資料,造成A事務所做操作丟失),因此mysql資料庫預設選擇的隔離級別是“可重複讀”級別,同時採用MVCC模型優化了系統性能。

     其中可重複讀可以做到讀讀並行,讀已提交寫鎖可以將讀鎖升級。在這“讀未提交”事務隔離級別下,如果當前事務正在寫,那麼其它所有的讀都將被阻塞(這裡的讀寫事務是針對相同的資源,或者說是針對資料庫的同一行資料),所以優化的點也在這裡,有沒有辦法讓寫不阻塞讀呢?這樣的話,可以大大提升資料庫讀的效能,尤其是在讀多寫少的場景下,這樣的效能優化尤其重要。

    MVCC(多版本併發控制)模型為解決這個問題提供了思路。在MVCC併發控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。當前讀,讀取的是記錄的最新版本,並且當前讀返回的記錄,都會加上鎖,保證其他事務不會再併發修改這條記錄。

那哪些讀操作是快照讀?哪些操作又是當前讀呢?以MySQL InnoDB為例:

快照讀:簡單的select操作,屬於快照讀,不加鎖:

select * from table where A=?;

當前讀:特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。

select * from table where A=? lock in share mode;

select * from table where A=? for update;

insert into table values (…);

update table set A=? where B=?;

delete from table where A=?;

所有以上的語句,都屬於當前讀,讀取記錄的最新版本。並且讀取之後,還需要保證其它併發事務不能修改當前記錄,對讀取記錄加鎖。其中除了第一條語句,對讀取記錄加S鎖 (共享鎖)外,其它的操作,都加的是X鎖 (排它鎖)。