1. 程式人生 > >數據庫知識之事務

數據庫知識之事務

事務日誌 相關 數據庫 class 得到 現象 現實 操作系統 數據

事務(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.在當前事務完成之前,其它事務所插入的新記錄,其索引鍵值不能在當前事務的任何語句所讀取的索引鍵範圍中。

數據庫知識之事務