以下內容選自《從PAXOS到ZOOKEEPER分布一致性原理與實踐》
事務(Transaction)是由一些列對系統中數據進行訪問與更新的操作所組成的一個程序執行邏輯單元,狹義上的事務特指數據庫事務。一方面,當多個應用程序並發訪問數據庫時,事務可以在這些應用程序之間提供一個隔離方法,以防止彼此的操作互相干擾。另一方面,事務為數據庫操作提供了一個從失敗中恢復到正常狀態的方法,同時提供了數據庫即使在異常狀態下仍能保持數據一致性的方法。
事務具有四個特征,分別是原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、和持久性(Durability),簡稱為事務的ACID特性。
原子性
事務的原子性是指事務必須是一個原子的操作序列單元。事務中包含的各項操作在一次執行過程中,只允許出現以下兩種狀態之一。
- 全部成功執行。
- 全部不執行。
任何一項操作失敗都將導致整個事務失敗,同時其他已經被執行的操作都將被撤銷並回滾,只有所有的操作全部成功,整個事務才算是成功完成。
一致性
事務的一致性是指事務的執行不能破壞數據庫的完整性和一致性,一個事務在執行之前和執行之后,數據庫都必須處於一致性狀態。也就是說,事務執行的結果必須是使數據庫從一個一致性狀態轉移到另一個一致性狀態,因此當數據庫只包含成功事務提交的結果時,就能說數據庫處於一致性狀態。而如果數據庫在運行過程中發生故障,有些事務尚未完后就被迫中斷,這些未完成的事務對數據庫所做的修改有一部分已寫入物理數據庫,這時數據庫就處於一種不正確的狀態,或者說是不一致的狀態。
隔離性
事務的隔離性是指在並發環境中,並發的事務是相互隔離的,一個事務的執行不能被其他事務干擾。也就是說,不同的事務並發操作相同的數據時,每個事務都有各自完整的數據空間,即一個事務內部的操作及使用的數據對其他並發事務是隔離的,並發執行的各個事務之間不能相互干擾。
在標准SQL規范中,定義了4個事務隔離級別,不同的隔離級別對事務的處理不同,如未授權讀取、授權讀取、可重復讀取和串行化。
未授權讀取
未授權讀取也被成為讀未提交(Read Uncommitted),該隔離級別允許臟讀取,其隔離級別最低。換句話說,如果一個事務正在處理某一項數據,並對其進行了更新,但同時尚未完成事務,因此還沒有進行事務提交;而與此同時,允許另一個事務也能夠訪問該數據。舉個例子來說,事務A和事務B同時進行,事務A在整個執行階段,會將某數據項的值從1開始,做一些列加法操作(比如說加1操作)知道變成10之后進行事務提交,此時事務B能夠看到這個數據項在事務A操作過程中的所有中間值(如1變成2、2變成3等),而對這一些列的中間值的對去就是未授權讀取。
授權讀取
授權讀取也被稱為讀已提交(Read Committed),它和未授權讀取非常相近,唯一的區別就是授權讀取只允許獲取已經被提交的數據。同樣以上面的例子來說,事務A和事務B同時進行,事務A進行與上述同樣的操作,此時事務B無法看到這個數據項在事務A操作過程的所有中間值,只能看到最終的10。另外,如果說一個事務C。和事務A進行非常類似的操作,只是事務C是將數據項從10加到20,此時事務B同樣可以讀取到20,即授權讀取允許不可重復讀取。
可重復讀取
可重復讀取(Repeatable Read),簡單地說,就是保證在事務處理過程中,多次讀取同一個數據時,其值都和事務開始時刻是一致的。因此該事物級別禁止了不可重復讀取和臟讀取,但是有可能出現幻影數據。所謂幻影數據,就是指同樣的事務操作,在前后兩個時間段內執行對同一個數據項的讀取,可能出現不一致的結果。在上面的例子,可重復讀取隔離級別能夠保證事務B在第一次事務操作過程,始終對數據項讀取到1,但是在下一次事務操作中,即使事務B(注意,事務名字雖然相同,但是指的是另一次事務操作)采用同樣的查詢方式,就可能會讀取到10或20。
串行化
串行化(Serializable)是最嚴格的事務隔離級別。它要求所有事務都被串行執行,即事務只能一個接一個地進行處理,不能並發執行。
以上4個隔離級別的隔離性一次增強,分別解決了不同的問題,下表對這4個隔離級別進行了一個簡單的對比。
隔離級別 | 臟讀 | 可重復讀 | 幻讀 |
未授權讀取 | 存在 | 不可以 | 存在 |
授權讀取 | 不存在 | 不可以 | 存在 |
可重復讀取 | 不存在 | 可以 | 存在 |
串行化 | 不存在 | 可以 | 不存在 |
事務隔離級別越高,就越能保證數據的完整性和一致性,但同時對並發性能的影響也越大。通常,對於絕大多數的應用程序來說,可以優先考慮將數據庫系統的隔離級別設置為授權讀取,這能夠在避免臟讀取的同時保證較好的並發性能。盡管這種事務隔離級別會導致不可重復讀、虛讀和第二類丟失更新等並發問題,但較為科學的做法是在可能出現這類問題的個別場合中,由應用程序主動采用悲觀鎖或樂觀鎖來進行事務控制。
持久性
事務的持久性也被稱為永久性,是指一個事務一旦提交,它對數據庫中對應數據的狀態變更就應該是永久性的。換句話說,一旦某個事務成功結束,那么它對數據庫所做的更新就必須被永久保存下來--即使發生系統崩潰或機器宕機等故障,只要數據庫能夠重新啟動,那么一定能夠將其恢復到事務成功結束時的狀態。
以下內容選自微信公眾號--java一日一條《深入理解spring事務原理》
spring事務傳播機制
所謂spring事務的傳播機制,就是定義在存在多個事務同時存在的時候,spring應該如何處理這些事務的行為。
名稱 | 解釋 |
PROPAGATION_REQUIRED | 支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇,也是spring默認的事務的傳播。 |
PROPAGATION_REQUIRES_NEW | 新建事務,如果當前存在事務,把當前事務掛起。新建的事務將和被掛起的事務沒有任何關系,是兩個獨立的事務,外層事務失敗回滾之后,不能回滾內層事務執行的結果,內層事務失敗拋出異常,外層事務捕獲,也可以不處理回滾操作。 |
PROPAGATION_SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
PROPAGATION_MANDATORY | 支持當前事務,如果當前沒有事務,就拋出異常。 |
PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 |
PROPAGATION_NEVER | 以非事務方式執行,如果當前存在事務,則拋出異常。 |
PROPAGATION_NESTED | 如果一個活動的事務存在,則運行在一個嵌套的事務中。如果沒有活動事務,則按REQUIRED屬性執行。它使用了一個單獨的事務,這個事務擁有多個可以回滾的保存點。內部事務的回滾不會對外部事務造成影響。它只對DataSourceTransactionManager事務管理器起效。 |