-
什么是事務?
事務(Transaction):是訪問并可能更新數據庫中各種數據項的一個程序執行單元(unit)。
例如:在關系數據庫中,一個事務可以是一條SQL語句,一組SQL語句或整個程序。
-
事務的四大屬性(ACID)
事務具有四個屬性,也是我們常說的ACID
。
原子性(Atomicity):一個事務是一個不可分割的工作單位,事務中包括的諸操作要么都做,要么都不做。
簡單來說就是把一些操作封裝成一個整體,整體操作要么完成,要么整體內部一個都不做。
一致性(Consistency):事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。
簡單來說就是對存到數據庫的合法性進行校驗,對于合法的數據都應該能夠存到數據庫中,對于不合法的數據都不應該存入數據庫中。
譬如:
一個User表,里面存放userName、age、address等字段
這時對于任意一個滿足User表字段的數據都應該能夠正確存入
如果此時有一個Course對象,里面存放courseName、courseTime、courseScore等字段,把這個Course對象存到剛剛的User表中,很顯然是錯誤的
隔離性(Isolation):一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對并發的其他事務是隔離的,并發執行的各個事務之間不能互相干擾。
簡單理解就是處理數據庫的并發操作,譬如,對于同一條數據此時有兩個數據庫請求同時訪問,一個是查詢,一個是更新,這個時候怎么保證數據的正確性就是由隔離性決定的。
持久性(Durability):持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。
簡單來說,就是數據可以永久存儲。
-
事務的隔離級別
上面說到了隔離性,隔離性的存在就是為了處理數據庫并發訪問帶來的數據安全性和正確性的問題,下面我們詳細說明:
1. read uncommitted(讀取未提交的事務)
字面意思就是讀取未提交,什么意思?
比如:
一個人在銀行有2000元,這時候另一個人轉賬給他,但是轉賬過程中發現錢出錯了,又撤銷了轉賬,而此時這個人又恰恰在撤銷轉賬之前查詢了賬戶余額,此時如果是`read uncommitted`級別,那么此時查詢的結果就是2000元+轉賬的金額,而事實上這個人賬戶還是2000元。
這就是明顯的臟數據問題,因為轉賬的事務動作還未最終完成,而當前這個人就能查詢到未提交的事務過程。(轉賬和撤銷轉賬是在同一個事務中)
2. read committed(讀取提交的事務)
這個時候我們修改隔離級別,改為讀取提交的事務級別,此時會怎么樣?
比如:
還是這個人有2000元,這個時候他自己在查詢賬戶余額,而此時又有一個人給他轉賬,轉賬過程可能還存在撤銷轉賬操作,但是由于是讀取提交的事務,在轉賬事務未提交之前,他始終讀取的都是原數據庫中的數據,2000元不變,只有當轉賬事務完成提交后,他讀取的才是轉賬后的數額。
3. repeatable read(重復讀取)
解決了臟數據的問題后還是存在另一個問題
比如:
一個事務中有兩次讀取同一條數據的操作,而另一個事務中則是對這條數據進行更新,這就會導致第一個事務第一次讀取時1,此時另一個事務執行提交將數據更新為2,那么第一個事務第二次讀取就是2,明細第一個事務的兩次對同一條數據的讀取是不正確的,即同一事物中對同一條數據的讀取是不重復的。
于是有了repeatable read
的隔離級別,它保證多個事務對同一條數據進行操作時,如果有讀取操作,那么就不允許事務對其進行更新操作。
比如:
A事務現在讀取數據庫,B事務有兩步:一是讀取,二是更新,然而發現A事務正在讀取數據,此時B事務只能讀取數據,不能執行對A讀的數據的更新操作。
4. Serializable(序列化)
到了第三個級別repeatable read就沒有問題了嗎?
如果A事務讀取數據庫,此時B事務有兩個操作:讀取之后更新,B事務發現A事務正在讀取。于是只能讀取,此時恰恰A事務執行完成,B事務的讀取也剛好完成,B事務發現已經沒有事務對數據進行讀操作了,這個時候就對數據進行了更新操作,之后A事務再回來查詢數據時發現數據又已經發生了改變,這就是常說的幻讀。
為了解決幻讀的可能,我們將數據庫的隔離級別提高到serializable,它將所有的事務都進行序列化,進行了排隊處理,每次只接受一個事務請求,只有一個事務結束后才進行下一個事務,絕對保證每個事務的正確執行,于是帶來的問題就是性能很低。
舉例:
A事務和B事務,B事務中有查詢和更新操作,在repeatable read下此時B事務先執行,但是執行到讀操作時,A事務進行查詢,此時B事務查詢完成發現有事務進行讀操作,于是更新操作無法完成。
這個時候A事務本應該查詢到B事務更新完成后的結果,但是卻查的更新前的結果。
在serializale下,B事務先執行,A事務排隊中,B事務執行結束后已經是更新后的結果,A事務拿到B事務更新后的結果值。