1. 程式人生 > >什麼是事務,事務的ACID特性

什麼是事務,事務的ACID特性

一.什麼是事務
事務是應用程式中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要麼全部成功,要麼一個都不做。
事務的結束有兩種,當事務中的所以步驟全部成功執行時,事務提交。如果其中一個步驟失敗,將發生回滾操作,撤消撤消之前到事務開始時的所以操作。

突出事物原子性操作,要麼都做,要麼撤銷回滾都不做。

二:事務的ACID特性

1. Atomicity(原子性)

原子性很容易理解,也就是說事務裡的所有操作要麼全部做完,要麼都不做,事務成功的條件是事務裡的所有操作都成功,只要有一個操作失敗,整個事務就失敗,需要回滾。
2. Consistency(一致性)
一致性也比較容易理解,也就是說資料庫要一直處於一致的狀態,事務開始前是一個一致狀態,事務結束後是另一個一致狀態,事務將資料庫從一個一致狀態轉移到另一個一致狀態。
3. Isolation(獨立性)
從字面上來說,獨立性是其中最難理解的一點,但如果結合
Oracle
中的undo,也就不難理解了。所謂的獨立性就是指併發的事務之間不會互相影響,如果一個事務要訪問的資料正在被另外一個事務修改,只要另外一個事務還未提交,它所訪問的資料就不受未提交事務的影響。換句話說,一個事務的影響在該事務提交前對其它事務是不可見的。
注意:這裡的Isolation跟隔離級別(Isolation Level)是無關的。
4. Durability(永續性)

永續性也不難理解,是指一旦事務提交後,它所做的修改將會永久的儲存在資料庫上,即使出現宕機也不會丟失。

三:理解事務ACID特性及隔離機制

理解原子性(Atomicity)

   原子性意味著資料庫中的事務執行是作為原子。即不可再分,整個語句要麼執行,要麼不執行。

   在SQL SERVER中,每一個單獨的語句都可以看作是預設包含在一個事務之中:



  所以,每一個語句本身具有原子性,要麼全部執行,這麼全部不執行,不會有中間狀態:


  上面說了,每一條T-SQL語句都可以看作是預設被包裹在一個事務之中的,SQL Server對於每一條單獨的語句都實現了原子性,但這種原子粒度是非常小的,如果使用者想要自己定義原子的大小,則需要包含在事務中來構成使用者自定義的原子粒度:


    對於使用者來說,要用事務實現的自定義原子性往往是和業務相關的,比如銀行轉賬,從A賬戶減去100,在B賬戶增加100,如果這兩個語句不能保證原子性的話,比如從A賬戶減去100後,伺服器斷電,而在B賬戶中卻沒有增加100.雖然這種情況會讓銀行很開心,但作為開發人員的你可不希望這種結果.而預設事務中,即使出錯了也不會整個事務進行回滾。而是失敗的語句丟擲異常,而正確的語句成功執行。這樣會破壞原子性。所以SQL SERVER給予了一些選項來保證事務的原子性.


SQL SERVER提供了兩大類方式來保證自定義事務的原子性:

  1.通過SET XACT_ABORT ON來設定事務必須符合原子性

利用設定XACT_ABORT選項設定為ON,來設定所有事務都作為一個原子處理.下面例子利用兩個語句插入到資料庫,可以看到開啟SET XACT_ABORT ON選項後,事務具有了原子性:


 2.按照使用者設定進行回滾(ROLLBACK)

這種方式具有更高的靈活性,開發人員可以自定義在什麼情況進行ROLLBACK,利用TRY CATCH語句和@@ERROR進行判斷都屬於這種方式.


理解一致性(Consistency)

     一致性,即在事務開始之前和事務結束以後,資料庫的完整性約束沒有被破壞

     一致性分為兩個層面

    1.資料庫機制層面

資料庫層面的一致性是,在一個事務執行之前和之後,資料會符合你設定的約束(唯一約束,外來鍵約束,Check約束等)和觸發器設定.這一點是由SQL SERVER進行保證的.

     2.業務層面

對於業務層面來說,一致性是保持業務的一致性.這個業務一致性需要由開發人員進行保證.很多業務方面的一致性可以通過轉移到資料庫機制層面進行保證.比如,產品只有兩個型號,則可以轉移到使用CHECK約束使某一列必須只能存這兩個型號.

比如你定義一個事務,裡面的操作是A,B,C三步,系統原子效能保證的是這三步要麼都執行,要麼都不執行,不可拆分。但是有可能你這三部破壞了資料的一致性,比如你定義了從A賬戶劃撥200塊給B賬戶。如果你的事務裡只包含從A賬戶扣款,而不包含B賬戶加錢。那麼系統保證原子性後,能保證要麼從A賬戶都扣款成功,要麼都不成功,不會出現扣了一半款之類的異常情況。但是沒辦法保證B賬戶加錢了。所以A賬戶扣款,B賬號加錢,這是一個連續的動作,業務邏輯上要保證一致性,所以必須把兩個步驟放在一個事務裡,這樣才能保證一致性。

理解隔離性(Isolation)

    隔離性:指的是在併發環境中,發事務之間互相影響的程度(即併發事務間資料的可見程度)當不同的事務同時操縱相同的資料時,每個事務都有各自的完整資料空間。由併發事務所做的修改必須與任何其他併發事務所做的修改隔離。事務檢視資料更新時,資料所處的狀態要麼是另一事務修改它之前的狀態,要麼是另一事務修改它之後的狀態,事務不會檢視到中間狀態的資料

    在Windows中,如果多個程序對同一個檔案進行修改是不允許的,Windows通過這種方式來保證不同程序的隔離性:


而SQL Server中,通過SQL SERVER對資料庫檔案進行管理,從而可以讓多個程序可以同時訪問資料庫:


 事務間的相互影響

SQL Server利用加鎖和阻塞來保證事務之間不同等級的隔離性.

    一般情況下,完全的隔離性是不現實的,完全的隔離性要求資料庫同一時間只執行一條事務(即事務的執行時序列化的),這樣的效能可想而知.想要理解SQL Server中對於隔離性的保障,首先要了解事務之間是如何幹擾的.但是同一個事務內的資料庫操作的資料是透明的,即同一個事務內的一個數據庫操作可以讀取另一個未提交(commit)的資料庫操作。

    事務之間的互相影響的情況分為幾種,分別為:髒讀(Dirty Read),不可重複讀(Non-Repeatable Reads),幻讀(Phantom Reads)

髒讀

髒讀意味著一個事務讀取了另一個事務未提交的資料,而這個資料是有可能回滾的:


下面來看一個例子:

     兩個事務,事務A插入一條資料,但未提交,事務B在此期間進行了讀取,讀取到了事務A未提交的資料,造成髒讀


不可重複讀(Unrepeatable Read)

     不可重複讀意味著,在資料庫訪問中,一個事務先後讀取同一條記錄,但兩次讀取的資料不同,我們稱之為不可重複讀。也就是說,這個事務在兩次讀取之間該資料被其它事務所修改。就是說事務A中兩處讀取資料,第一次讀時是100,然後事務B把值改成了200,事務A再讀一次,結果就發現值變了,造成A事務資料混亂。

幻讀(phantom read)

幻讀,和不可重複讀相似,也是同一個事務中多次讀不一致的問題。但是不可重複讀的不一致是因為它所要取的資料集被改變了而幻讀所要讀的資料不一致卻不是他所要讀的資料改變,而是它的條件資料集改變。比如:Select id where name="ppgogo*",第一次讀去了6個符合條件的id,第二次讀時,由於事務B把第一個貼的名字由"dd"改成了“ppgogo9”,結果取出來7個數據,就好象發生了幻覺一樣.


事務間相互影響解決方案--設定隔離級別

為了避免上述幾種事務之間的影響,通過設定不同的隔離等級來進行不同程度的避免。因為高的隔離等級意味著更多的鎖,從而犧牲效能.所以這個選項開放給了使用者根據具體的需求進行設定。不過預設的隔離等級Read Commited符合了99%的實際需求.事務隔離級別的出現,是為了使你在效能與資料的有效性之間做一個平衡,不是說級別越高越好,只有合適才是最好的。

   隔離事務之間的影響是通過鎖來實現的,這個概念比較繁雜,所以本文不會詳細對這個概念進行講解.通過阻塞來阻止上述效果

    SQL Server提供了5種選項來避免不同級別的事務之間的影響

    隔離等級由低到高分別為

    1)未提交讀(Read Uncommitted)(最高的效能,但可能出現髒讀,不可重複讀,幻讀): SELECT語句以非鎖定方式被執行.

    2)提交讀(Read Committed)(可能出現不可重複讀,幻讀)只能讀取到已經提交的資料。

   3)可重複讀(Repeated Read)(可能出現幻讀):通過加共享記錄鎖實現,即 SELECT .... FOR UPDATE

    4)序列讀(Serializable)(最低的效能,Range鎖會導致併發下降)完全的序列化讀,所有SELECT語句都被隱式的轉換成SELECT ... LOCK IN SHARE MODE,即讀取使用表級共享鎖,讀寫相互都會阻塞。隔離級別最高。

  5  SNOPSHOT(這個是通過在tempDB中建立一個額外的副本來避免髒讀,不可重複讀,會給tempDB造成額外負擔,因為不是標準ANSI SQL標準,不詳細討論)

 隔離級別對比表:


總之,不同的隔離級別是通過加不同的鎖,造成阻塞來實現的,來看一個例子:

    SQL SERVER通過阻塞來阻止髒讀,所以保持獨立性會以付出效能作為代價:


理解永續性(Durability)

  永續性,意味著在事務完成以後,該事務所對資料庫所作的更改便持久的儲存在資料庫之中,並不會被回滾。

     即使出現了任何事故比如斷電等,事務一旦提交,則持久化儲存在資料庫中.

     SQL SERVER通過write-ahead transaction log來保證永續性。write-ahead transaction log的意思是,事務中對資料庫的改變在寫入到資料庫之前,首先寫入到事務日誌中。而事務日誌是按照順序排號的(LSN)。當資料庫崩潰或者伺服器斷點時,重啟動SQL SERVER,SQL SERVER首先會檢查日誌順序號,將本應對資料庫做更改而未做的部分持久化到資料庫,從而保證了永續性.

總結:

事務的(ACID)特性是由關係資料庫管理系統(RDBMS,資料庫系統)來實現的。資料庫管理系統採用日誌來保證事務的原子性、一致性和永續性。日誌記錄了事務對資料庫所做的更新,如果某個事務在執行過程中發生錯誤,就可以根據日誌,撤銷事務對資料庫已做的更新,使資料庫退回到執行事務前的初始狀態。

資料庫管理系統採用鎖機制來實現事務的隔離性。當多個事務同時更新資料庫中相同的資料時,只允許持有鎖的事務能更新該資料,其他事務必須等待,直到前一個事務釋放了鎖,其他事務才有機會更新該資料。