根據維基百科的定義,一個數據庫事務一般包含了一個序列的對數據庫的讀/寫操做。它的存在包含有如下兩個目的:1)爲數據庫操做序列提供了一個從失敗中恢復到正常狀態的方法,同時提供了數據庫即便在異常狀態下仍能保持一致性的方法;2)當多個應用程序在併發訪問數據庫時,能夠在這些應用程序之間提供一個隔離方法,以防止彼此的操做互相干擾。簡單來說,事務的做用至少有兩個:保證數據一致性,以及對數據進行隔離。這麼說你們可能還不太好理解,咱們仍是舉個例子說明一下吧。數據庫
咱們以A向B轉帳100塊錢爲例,在一筆轉帳操做中,至少必須包含2個操做:服務器
將A的帳戶餘額扣除100塊錢(假設轉帳前A的帳戶餘額大於100塊錢)併發
將B的帳戶餘額增長100塊錢性能
若是在轉帳的過程當中不使用事務,那麼有可能會出如今將A的帳戶扣除100塊錢以後,發生了不可預知的異常(比方說服務器宕機了),致使沒來得及將B的帳戶增長100塊錢,如此一來,數據庫就產生了數據不一致的狀況,即A的帳戶扣了100塊錢,可是B的帳戶並無相應地增長100塊錢,也就是說有100塊錢「不知去向」了。而若是將這2個操做放在一個事務裏執行的話,因爲事務中的操做要麼所有執行,要麼所有不執行,因此能夠保證數據一致性。這就是在數據一致性要求比較高的場景下使用事務的好處。事務
事務的特性主要有4個:原子性,一致性,隔離性與持久性,也叫作ACID。io
原子性,指的是一個事務必須被視爲一個不可分割的最小工做單元,整個事務中的操做要麼所有提交成功,要麼所有失敗回滾,也就是說不可能只執行事務中的部分操做,這就是事務的原子性。class
一致性,指的是事務應確保數據庫的狀態從一個一致狀態轉變爲另外一個一致狀態。以上述轉帳的例子爲例,轉帳後A的帳戶減小100塊錢,B的帳戶增長100塊錢是知足數據一致性的,事務能夠保證事務成功提交以後數據庫轉化爲這個狀態,若是事務失敗回滾了,則仍是保持最初的一致性狀態,而不會出現上述的A的帳戶減小100塊錢,B的帳戶沒有變化的不一致的中間狀態。程序
隔離性,指的是多個事務併發執行時,一個事務的執行不該影響其餘事務的執行。好比當A向B轉帳的過程當中,B也能夠向A轉帳,這2個事務互不影響,並且一般來說也是互不可見的(注意,是一般來說「不可見」,後續講到事務隔離級別的時候再詳述)。方法
持久性,指的是已被提交的事務對數據庫的修改應該被永久保存在數據庫中。這個比較好理解,就是說已成功提交的事務會被永久地保存下來。統計
前文說到,事務具備隔離性,並且一般來說,不一樣事務之間是不可見的,然而現實中的事務隔離性並不都是不可見的,實際上,SQL標準定義了4種事務隔離級別:讀未提交,讀已提交,可重複讀,串行化,下文將逐一講解。
讀未提交,指的是事務中未提交的修改,對於其餘事務而言是可見的,這是隔離性最低的一種級別了。在這種隔離級別下,會出現「髒讀」的狀況。所謂「髒讀」指的是讀取到了其餘事務未提交的數據。咱們以2個事務同時進行爲例,由於事務A能夠讀到事務B的未提交的修改數據,假如說事務B在事務A結束以前由於發生異常而回滾了,那麼A讀到的事務B的未提交的數據就是「過時」的,若是事務A在這個「過時」數據上進行操做,那勢必會形成數據不一致的狀況。所以這種隔離級別在實際中不多使用。
讀已提交,指的是一個事務開始時,只能看到其餘已經提交的事務對數據所作的修改。這種隔離級別能夠防止「髒讀」的問題出現。可是這種狀況可能會出現「不可重複讀」的問題。所謂不可重複讀是指,事務A前後2次讀到的數據不一致。舉個例子,事務A先讀到小明的帳戶餘額爲100塊錢,而後再作了其餘操做(假設這些操做沒有改變小明的餘額),這個時候事務B將小明的帳戶扣了10塊錢,變成90塊錢了並提交了,因爲事務A能夠讀到事務B提交的修改數據,因此當事務A執行了其餘操做後再讀取小明的餘額時就變成90塊了,所以先後2次讀取的數據不一致,故出現了「不可重複讀」的問題。
可重複讀,指的是能夠避免上述「不可重複讀」的狀況出現,即它能夠保證在同個事務中,前後讀到的同一行數據是一致的,然而這種隔離級別下會出現另外一個問題,就是「幻象讀」。「幻象讀」指的是事務A讀取到了事務B新增的數據,所以出現了「幻行」。舉個例子,事務A一開始查詢到小明在1月份一共網購了100次,而後再進行其餘操做(假設這些操做沒有改變小明的網購記錄數),而後事務B插入了一條小明新的網購記錄並提交了,接下來事務A再統計出小明的網購記錄,變成101次了,出現了「幻行」,也就是出現了「幻象讀」。
串性化,指的是強制事務串行執行,其能夠避免「幻象讀」的問題出現,這是最嚴格的隔離級別了。由於串行化須要在發生競爭的數據上加鎖,因此併發性能不高,只有在對數據一致性要求很是高且併發度不高的狀況下才會考慮使用這種隔離級別。