標籤:幻讀 資料庫操作 and 特性 讀寫 儲存介質 sans 應用 其他
事務(Transaction),一般是指要做的或所做的事情。在電腦術語中是指訪問並可能更新資料庫中各種資料項目的一個程式執行單元(unit)。在電腦術語中,事務通常就是指資料庫事務。
概念
一個資料庫事務通常包含對資料庫進行讀或寫的一個操作序列。它的存在包含有以下兩個目的:
1、為資料庫操作提供了一個從失敗中恢複到正常狀態的方法,同時提供了資料庫即使在異常狀態下仍能保持一致性的方法。2、當多個應用程式在並發訪問資料庫時,可以在這些應用程式之間提供一個隔離方法,以防止彼此的操作互相干擾。
當一個事務被提交給了DBMS(資料庫管理系統),則DBMS需要確保該事務中的所有操作都成功完成且其結果被永久儲存在資料庫中,如果事務中有的操作沒有成功完成,則事務中的所有操作都需要被復原,回到事務執行前的狀態(要麼全執行,要麼全都不執行);同時,該事務對資料庫或者其他事務的執行無影響,所有的事務都好像在獨立的運行。
但在現實情況下,失敗的風險很高。在一個資料庫事務的執行過程中,有可能會遇上事務操作失敗、資料庫系統/作業系統失敗,甚至是儲存介質失敗等情況。這便需要DBMS對一個執行失敗的交易執行恢複操作,將其資料庫狀態恢複到一致狀態(資料的一致性得到保證的狀態)。為了實現將資料庫狀態恢複到一致狀態的功能,DBMS通常需要維護交易記錄以追蹤事務中所有影響資料庫資料的操作。
特性
事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為ACID特性。
原子性:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被復原(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性:在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續資料庫可以自發性地完成預定的工作。
隔離性:資料庫允許多個並發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務並發執行時由於交叉執行而導致資料的不一致。事務隔離分為不同層級,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和序列化(Serializable)。
持久性:交易處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。
舉例
用一個常用的“A賬戶向B帳號匯錢”的例子來說明如何通過資料庫事務保證資料的準確性和完整性。熟悉關係型資料庫事務的都知道從帳號A到帳號B需要6個操作:
1、從A帳號中把餘額讀出來(500)。
2、對A帳號做減法操作(500-100)。
3、把結果寫回A帳號中(400)。
4、從B帳號中把餘額讀出來(500)。
5、對B帳號做加法操作(500+100)。
6、把結果寫回B帳號中(600)。
原子性:
保證1-6所有過程要麼都執行,要麼都不執行。一旦在執行某一步驟的過程中發生問題,就需要執行復原操作。 假如執行到第五步的時候,B賬戶突然不可用(比如被登出),那麼之前的所有操作都應該復原到執行事務之前的狀態。
一致性
在轉賬之前,A和B的賬戶中共有500+500=1000元錢。在轉賬之後,A和B的賬戶中共有400+600=1000元。也就是說,資料的狀態在執行該事務操作之後從一個狀態改變到了另外一個狀態。同時一致性還能保證賬戶餘額不會變成負數等。
隔離性
在A向B轉賬的整個過程中,只要事務還沒有提交(commit),查詢A賬戶和B賬戶的時候,兩個賬戶裡面的錢的數量都不會有變化。如果在A給B轉賬的同時,有另外一個事務執行了C給B轉賬的操作,那麼當兩個事務都結束的時候,B賬戶裡面的錢應該是A轉給B的錢加上C轉給B的錢再加上自己原有的錢。
持久性
一旦轉賬成功(事務提交),兩個賬戶的裡面的錢就會真的發生變化(會把資料寫入資料庫做持久化儲存)!
原子性與隔離行
一致性與原子性是密切相關的,原子性的破壞可能導致資料庫的不一致,資料的一致性問題並不都和原子性有關。比如剛剛的例子,在第五步的時候,對B賬戶做加法時只加了50元。那麼該過程可以符合原子性,但是資料的一致性就出現了問題。
因此,事務的原子性與一致性缺一不可。
髒讀
髒讀就是指當一個事務正在訪問資料,並且對資料進行了修改,而這種修改還沒有提交到資料庫中,這時,另外一個事務也訪問這個資料,然後使用了這個資料。
e.g.? 1.Mary的原工資為1000, 財務人員將Mary的工資改為了8000(但未提交事務)? 2.Mary讀取自己的工資 ,發現自己的工資變為了8000,歡天喜地!? 3.而財務發現操作有誤,復原了事務,Mary的工資又變為了1000? 像這樣,Mary記取的工資數8000是一個髒資料。
不可重複讀取
是指在一個事務內,多次讀同一資料。在這個事務還沒有結束時,另外一個事務也訪問該同一資料。那麼,在第一個事務中的兩次讀資料之間,由於第二個事務的修改,那麼第一個事務兩次讀到的的資料可能是不一樣的。這樣在一個事務內兩次讀到的資料是不一樣的,因此稱為是不可重複讀取。? e.g.? 1.在事務1中,Mary 讀取了自己的工資為1000,操作並沒有完成? 2.在事務2中,這時財務人員修改了Mary的工資為2000,並提交了事務.? 3.在事務1中,Mary 再次讀取自己的工資時,工資變為了2000
解決辦法:如果只有在修改事務完全提交之後才可以讀取資料,則可以避免該問題。
幻讀
是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。
e.g. 目前工資為1000的員工有10人。 1.事務1,讀取所有工資為1000的員工。 2.這時事務2向employee表插入了一條員工記錄,工資也為1000 3.事務1再次讀取所有工資為1000的員工 共讀取到了11條記錄, 解決辦法:如果在操作事務完成資料處理之前,任何其他事務都不可以添加新資料,則可避免該問題
不可重複讀取的重點是修改 :
同樣的條件, 你讀取過的資料,再次讀取出來發現值不一樣了
幻讀的重點在於新增或者刪除
同樣的條件, 第 1 次和第 2 次讀出來的記錄數不一樣
JDBC交易隔離等級
ANSI/ISO SQL定義的標準隔離等級有四種,從高到底依次為:可序列化(Serializable)、可重複讀(Repeatable reads)、提交讀(Read committed)、未提交讀(Read uncommitted)。
未提交讀(Read uncommitted):未提交讀(READ UNCOMMITTED)是最低的隔離等級。在這種交易隔離等級下,一個事務可以讀到另外一個事務未提交的資料。未提交讀會導致髒讀
提交讀(Read committed):提交讀(READ COMMITTED)也可以翻譯成讀已提交,在一個事務修改資料過程中,如果事務還沒提交,其他事務不能讀該資料。提交讀這種隔離等級保證了讀到的任何資料都是提交的資料,避免了髒讀(dirty reads)。但是不保證事務重新讀的時候能讀到相同的資料,因為在每次資料讀完之後其他事務可以修改剛才讀到的資料。所以提交讀不能解決不可重複讀取的讀現象。
可重複讀(Repeatable reads):可重複讀(REPEATABLE READS),由於提交讀隔離等級會產生不可重複讀取的讀現象。所以,比提交讀更高一個層級的隔離等級就可以解決不可重複讀取的問題。這種隔離等級就叫可重複讀。可重複讀隔離等級可以解決不可重複讀取的讀現象。但是可重複讀這種隔離等級中,但是它解決不了幻讀
可序列化(Serializable):可序列化(Serializable)是最高的隔離等級,前面提到的所有的隔離等級都無法解決的幻讀,在可序列化的隔離等級中可以解決。雖然可序列化解決了髒讀、不可重複讀取、幻讀等讀現象。但是序列化事務會產生以下效果:
1.無法讀取其它事務已修改但未提交的記錄。
2.在當前事務完成之前,其它事務不能修改目前事務已讀取的記錄。
3.在當前事務完成之前,其它事務所插入的新記錄,其索引索引值不能在當前事務的任何語句所讀取的索引鍵範圍中。
資料庫知識之事務