1、介紹下Spring中的事務處理
資料庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要麼完全地執行,要麼完全地不執行。 事務處理可以確定除非事務性單元内的所有操作都成功完成,否則不會永久更新面向資料的資源。通過将一組相關操作組合為一個要麼全部成功要麼全部失敗的單元,可以簡化錯誤恢複并使應用程式更加可靠。一個邏輯工作單元要成為事務,必須滿足所謂的ACID(原子性、一緻性、隔離性和持久性)屬性。事務是資料庫運作中的邏輯工作機關,由DBMS中的事務管理子系統負責事務的處理。
- 原子性(Atomicity):一個事務是一個不可分割的工作機關,事務中包括的動作要麼都做要麼都不做。
- 一緻性(Consistency):事務必須保證資料庫從一個一緻性狀态變到另一個一緻性狀态,一緻性和原子性是密切相關的。
- 隔離性(Isolation):一個事務的執行不能被其它事務幹擾,即一個事務内部的操作及使用的資料對并發的其它事務是隔離的,并發執行的各個事務之間不能互相打擾。
- 持久性(Durability):持久性也稱為永久性,指一個事務一旦送出,它對資料庫中資料的改變就是永久性的,後面的其它操作和故障都不應該對其有任何影響。
在Spring中事務的實作的兩種方式:
- 基于XML聲明式事務
- 基于注解的使用
事務的傳播行為:
事務行為 | 說明 |
PROPAGATION_REQUIRED | 支援目前事務,假設目前沒有事務。就建立一個事務 |
PROPAGATION_SUPPORTS | 支援目前事務,假設目前沒有事務,就以非事務方式運作 |
PROPAGATION_MANDATORY | 支援目前事務,假設目前沒有事務,就抛出異常 |
PROPAGATION_REQUIRES_NEW | 建立事務,假設目前存在事務。把目前事務挂起 |
PROPAGATION_NOT_SUPPORTED | 以非事務方式運作操作。假設目前存在事務,就把目前事務挂起 |
PROPAGATION_NEVER | 以非事務方式運作,假設目前存在事務,則抛出異常 |
PROPAGATION_NESTED | 如果目前存在事務,則在嵌套事務内執行。如果目前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
ServiceA {
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
void methodB() {
}
}
如果methodA()方法中調用了 this.b(),這時b方法中的事務會生效嗎?
AopContext.currentProxy();
具體的聲明案例
@Transactional(propagation=Propagation.REQUIRED)
如果有事務, 那麼加入事務, 沒有的話建立一個(預設情況下)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不為這個方法開啟事務
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事務,都建立一個新的事務,原來的挂起,新的執行完畢,繼續執行老的事務
@Transactional(propagation=Propagation.MANDATORY)
必須在一個已有的事務中執行,否則抛出異常
@Transactional(propagation=Propagation.NEVER)
必須在一個沒有的事務中執行,否則抛出異常(與Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean調用這個方法,在其他bean中聲明事務,那就用事務.如果其他bean沒有聲明事務,那就不用事務.
事務的隔離級别
事務隔離級别指的是一個事務對資料的修改與另一個并行的事務的隔離程度,當多個事務同時通路相同資料時,如果沒有采取必要的隔離機制,就可能發生以下問題:
- 髒讀:一個事務讀到另一個事務未送出的更新資料,所謂髒讀,就是指事務A讀到了事務B還沒有送出的資料,比如銀行取錢,事務A開啟事務,此時切換到事務B,事務B開啟事務-->取走100元,此時切換回事務A,事務A讀取的肯定是資料庫裡面的原始資料,因為事務B取走了100塊錢,并沒有送出,資料庫裡面的賬務餘額肯定還是原始餘額,這就是髒讀
- 幻讀:是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的資料進行了修改,這種修改涉及到表中的全部資料行。同時,第二個事務也修改這個表中的資料,這種修改是向表中插入一行新資料。那麼,以後就會發生操作第一個事務的使用者發現表中還有沒有修改的資料行,就好象發生了幻覺一樣。
- 不可重複讀:在一個事務裡面的操作中發現了未被操作的資料,比方說在同一個事務中先後執行兩條一模一樣的select語句,期間在此次事務中沒有執行過任何DDL語句,但先後得到的結果不一緻,這就是不可重複讀
Spring中支援的隔離級别
隔離級别 | 描述 |
DEFAULT | 使用資料庫本身使用的隔離級别 ORACLE(讀已送出) MySQL(可重複讀) |
READ_UNCOMITTED | 讀未送出(髒讀)最低的隔離級别,一切皆有可能。 |
READ_COMMITED | 讀已送出,ORACLE預設隔離級别,有幻讀以及不可重複讀風險。 |
REPEATABLE_READ | 可重複讀,解決不可重複讀的隔離級别,但還是有幻讀風險。 |
SERLALIZABLE | 串行化,最高的事務隔離級别,不管多少事務,挨個運作完一個事務的所有子事務之後才可以執行另外一個事務裡面的所有子事務,這樣就解決了髒讀、不可重複讀和幻讀的問題了 |