總覽:
spring
原子性(Atomicity)
原子性是指事務包含的全部操做要麼所有成功,要麼所有失敗回滾,這和前面兩篇博客介紹事務的功能是同樣的概念,所以事務的操做若是成功就必需要徹底應用到數據庫,若是操做失敗則不能對數據庫有任何影響。
一致性(Consistency)
一致性是指事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態,也就是說一個事務執行以前和執行以後都必須處於一致性狀態。
拿轉帳來講,假設用戶A和用戶B二者的錢加起來一共是5000,那麼無論A和B之間如何轉帳,轉幾回帳,事務結束後兩個用戶的錢相加起來應該還得是5000,這就是事務的一致性。
隔離性(Isolation)
隔離性是當多個用戶併發訪問數據庫時,好比操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離。
即要達到這麼一種效果:對於任意兩個併發的事務T1和T2,在事務T1看來,T2要麼在T1開始以前就已經結束,要麼在T1結束以後纔開始,這樣每一個事務都感受不到有其餘事務在併發地執行。
關於事務的隔離性數據庫提供了多種隔離級別,稍後會介紹到。
持久性(Durability)
持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即使是在數據庫系統遇到故障的狀況下也不會丟失提交事務的操做。數據庫
髒讀
兩個事務正在併發的執行,事實上最後結果應該是1500纔對,時間5時刻的查詢餘額爲0就是髒數據,事務A讀取了事務B中未提交的數據,這就是髒讀。併發
時間 | 事務A | 事務B |
---|---|---|
1 | 開始事務 | - |
2 | - | 開始事務 |
3 | - | 查詢餘額有1000 |
4 | - | 取出1000,餘額0 |
5 | 查詢餘額0 | - |
6 | - | 撤銷掉事務 |
7 | 存入500,餘額500 | - |
8 | 提交事務 | - |
不可重複讀
兩個事務正在併發的執行,結果A兩次讀取的結果不同,這是由於兩次查詢有間隔,期間被其餘事務修改並提交了事務,相比髒讀的區別是,不可重複讀是讀取另外一事務提交的數據。這種現象也是正常的,是因爲事務的隔離級形成的,可是在在某些特別的狀況下也是不容許的。this
時間 | 事務A | 事務B |
---|---|---|
1 | 開始事務 | - |
2 | - | 開始事務 |
3 | - | 查詢餘額有1000 |
4 | 查詢餘額1000 | - |
5 | 取出1000,餘額0 | |
6 | - | 提交事務 |
7 | 查詢餘額0 | - |
幻讀
兩個事務正在併發的執行,事務A第一次統計和第二統計的結果不同,是由於事務B新增了一條數據,和不可重複讀同樣,都是讀取了另一個事務的數據,不一樣的是不可重複讀查詢的是同一條數據,而幻讀則是針對批量的數據,或者說不可重複讀是A讀取了B的更新數據,幻讀是A讀取了B的新增數據。spa
時間 | 事務A | 事務B |
---|---|---|
1 | 開始事務 | - |
2 | - | 開始事務 |
3 | 統計總金額10000 | - |
4 | - | - |
5 | 存入100 | |
6 | - | 提交事務 |
7 | 統計總金額10100 | - |
明白上面的問題以後就明白爲何須要隔離級別了,不一樣的隔離級別能處理不一樣的併發事務問題,下表:3d
事務級別 | 髒讀 | 不可重複讀 | 幻覺讀 |
---|---|---|---|
READ_UNCOMMITTED | 容許 | 容許 | 容許 |
READ_COMMITTED | 禁止 | 容許 | 容許 |
REPEATABLE_READ | 禁止 | 禁止 | 容許 |
SERIALIZABLE | 禁止 | 禁止 | 禁止 |
MySQL默認的事務級別是REPEATABLE_READcode
JDBC | 訪問 | |
---|---|---|
TRANSACTION_READ_UNCOMMITTED | ur | 就是俗稱「髒讀」(dirty read),在沒有提交數據時可以讀到已經更新的數據 |
TRANSACTION_READ_COMMITTED | cs | 在一個事務中進行查詢時,容許讀取提交前的數據,數據提交後,當前查詢就能夠讀取到數據。update數據時候並不鎖住表 |
TRANSACTION_REPEATABLE_READ | rs | 在一個事務中進行查詢時,不容許讀取其餘事務update的數據,容許讀取到其餘事務提交的新增數據 |
TRANSACTION_SERIALIZABLE | rr | 在一個事務中進行查詢時,不容許任何對這個查詢表的數據修改。 |
事務怎麼傳播?方法A傳播到方法B。
Spring解決的就是方法之間的事務傳播。
下面看下每一種行爲具體表明的含義:blog
業務方法須要在一個事務中運行。若是方法運行時,已經處在一個事務中,那麼這個時候就會加入到該事務中,若是當前沒有事務環境的話,就會爲本身建立一個新的事務。圖片
這一事務屬性代表,若是業務方法A在某個事務範圍內被調用,則方法成爲事務的一部分。若是業務方法在事務範圍外被調用,則方法在沒有事務的環境下執行。即當標註了事務傳播屬性——SUPPORTS的業務方法在另外一個bean的業務方法中執行時,若是另外一個bean的業務方法開啓了事務,它就會處在事務中執行,若是另外一個bean的業務方法也沒開啓事務,那麼它也在沒有事務的環境中進行。事務
該屬性指定業務方法只能在一個已經存在的事務中執行,業務方法不能發起本身的事務。若是業務方法在沒有事務的環境下調用,容器就會拋出異常。一種比較強硬的方式。
該屬性代表無論當前是否存在事務,業務方法總會爲本身發起一個新的事務。若是方法已經運行在一個事務中,則原有事務會被掛起,新的事務會被建立,直到方法執行結束,新事務纔算結束,原先的事務纔會恢復執行。
聲明方法不須要事務。若是方法沒有關聯到一個事務,容器不會爲它開啓事務。若是方法在一個事務中被調用(在其餘業務bean的方法中被調用了,而其餘業務bean的方法是開啓了事務的),該事務會被掛起,在方法調用結束後,原先的事務便會恢復執行。
指定業務方法絕對不能在事務範圍內執行。若是業務方法在某個事務中執行,容器會拋出異常,只有業務方法沒有關聯到任何事務,才能正常執行。比較強硬的方式,就是不支持事務。
(嵌套事務)若是一個活動的事務存在,則當前方法運行在一個嵌套的事務中。 若是沒有活動事務,就建立一個新的事務。它使用了一個單獨的事務,這個事務擁有多個能夠回滾的保存點。內部事務的回滾不會對外部事務形成影響。外部事務回滾會致使內部事務的回滾。若是被調用的內部方法沒有捕獲異常,跑出異常也會致使外部事務的回滾。
看下Spring中枚舉定義的7種事務傳播行爲
package org.springframework.transaction.annotation; public enum Propagation { REQUIRED(0), SUPPORTS(1), MANDATORY(2), REQUIRES_NEW(3), NOT_SUPPORTED(4), NEVER(5), NESTED(6); private final int value; private Propagation(int value) { this.value = value; } public int value() { return this.value; } }
在使用註解方式的事務時候咱們能夠用下面的方式來設置事務的傳播行爲
@Transactional(propagation = Propagation.REQUIRED)
是否是很方便。
readOnly屬性:設置爲只讀事務,對於只讀事務,它就不能進行更新操做,通常只存在數據讀取的時候,能夠將readOnly屬性設置爲true,可提供效率。
timeout屬性:表明事務的超時時間,默認爲30s,通常狀況下都不須要設置超時時間。若是超過期間就回滾。