這段時間在工作中碰到乙個事務相關的問題。先說下這個問題的場景,我們是乙個**專案,正在開發優惠券模組,現在有乙個需求是需要批量領取優惠券,而且在領券時,其中一張領取失敗不能影響其他符合要求的券的領取。由於之前在開發時,在領券這一塊一直做的是單張領取,所以在做批量的時候很簡單的做了個迴圈,然後封裝成乙個批量領券的方法中。偽**如下:
@service
@transactional
(rollbackfor = exception.
class
)@slf4j
public
class
couponservice
// 自定義的異常類,專門指定不符合規則的券被領取時丟擲的狀態
throw
newcustomeexception
("不存在這個優惠券");
}/**
* 批量領取
* @param codes
* @return
*/public list
batchget
(list
codes)
catch
(customeexception e)
target.
add(coupon);}
);return target;
}}
上面的方法在執行時會丟擲異常
transaction rolled back because it has been marked as rollback-only
我們來分析下這個異常:
首先我們要知道,spring中事務的預設傳播機制是
propagation_required:如果存在乙個事務,則支援當前事務。如果沒有事務則開啟
在這種傳播機制下,batchget方法跟迴圈中的get方法會共享乙個事務,而在get方法丟擲異常時,這個事務已經被標記為rollback-only了,在這種情況下,batchget方法捕獲了這個異常並沒有繼續向上丟擲,所以會執行commit操作,而對乙個被標記成rollback-only的方法執行commit操作,就會丟擲以上錯誤。
我的解決辦法就是,在batcget方法上將事務的隔離級別設定為propagation_supports:如果存在乙個事務,支援當前事務。如果沒有事務,則非事務的執行
。
好了,這個異常我們分析完了,現在我們進入我們這篇文章需要學的主題內容,主要是事務的傳播機制及隔離級別。預期兩篇文章,一篇理想學習,一篇原始碼分析,原始碼分析將以springboot為主。希望能跟大家一起進步,學習,每天進步一點點就好~~~
ropagation_required:如果存在乙個事務,則支援當前事務。如果沒有事務則開啟
解釋:當a.methoda()和b.methodb()都打上required的事務標誌,執行a.methoda()方法的時候,看到上下文沒有事務,會新建乙個事務,當執行到b.methodb()的時候,發現上下文已經有事務了,則不會新建事務,用a.methoda()新建的那個事務。如果b.methodb()執行成功,a.methoda()執行失敗,那麼b.methodb()和a.methoda()都會回滾(用的都是a.methoda()的事務)
propagation_supports:如果存在乙個事務,支援當前事務。如果沒有事務,則非事務的執行
解釋:當b.methodb()打上propagation_supports的事務標誌,執行a.methoda()方法,當執行到b.methodb()的時候,會檢查上下文有沒有事務,如果a.methoda()有事務,則b.methodb()沿用該事務,反之b.methodb()就以非事物的方式執行
3.propagation_mandatory:如果已經存在乙個事務,支援當前事務。如果沒有乙個活動的事務,則丟擲異常
解釋:當b.methodb()打上propagation_mandatory的事務標誌,執行a.methoda()方法,當執行到b.methodb()的時候,會檢查上下文有沒有事務,如果a.methoda()有事務,則b.methodb()沿用該事務,如果沒有,則會丟擲異常
4.propagation_requires_new:總是開啟乙個新的事務。如果乙個事務已經存在,則將這個存在的事務掛起
解釋:當b.methodb()打上propagation_requires_new的事務標誌,執行a.methoda()方法,當執行到b.methodb()的時候,會檢查上下文有沒有事務,如果a.methoda()有事務,則會掛起a.methoda()的事務,新建乙個屬於b.methodb(),當b.methodb()的事務執行結束的時候,則會喚醒b.methodb()的事務。和propagation_required的差別在於回滾,當b.methodb()的事務提交後,a.methoda()執行失敗,只會回滾a.methoda不會回滾b.methodb(),當b.methodb()執行失敗,異常被a.methoda()方法catch到的話,a.methoda()事務不會回滾
propagation_not_supported:總是非事務地執行,並掛起任何存在的事務
解釋:當b.methodb()打上propagation_not_supported的事務標誌,執行a.methoda()方法,當執行到b.methodb()的時候,會檢查上下文有沒有事務,如果a.methoda()有事務,則會掛起a.methoda()的事務,當執行完b.methodb()方法的時候,a.methoda()方法繼續以事務的方式執行
propagation_never: 總是非事務地執行,如果存在乙個活動事務,則丟擲異常
解釋:當b.methodb()打上propagation_never的事務標誌,執行a.methoda()方法,當執行到b.methodb()的時候,會檢查上下文有沒有事務,如果有事務,則丟擲異常,如果沒有則以非事務執行
propagation_nested:如果乙個活動的事務存在,則執行在乙個巢狀的事務中. 如果沒有活動事務, propagation_required 屬性執行
解釋:當b.methodb()打上propagation_not_supported的事務標誌,執行a.methoda()方法,當執行到b.methodb()的時候,如果a.methoda()方法有事務,則會用當前事務,如果 b.methodb()執行失敗,只會回滾 b.methodb(),不會回滾a.methoda(),只有當a.methoda()執行完成後才會提交b.methodb()的事務,如果a.methoda()方法沒有事務,就會新建乙個事務;
事務隔離級別:
isolation_default,
isolation_read_uncommitted,
isolation_read_committed,
isolation_repeatable_read,
isolation_generalizable
1.isolation_default:這是乙個platfromtransactionmanager預設的隔離級別,使用資料庫預設的事務隔離級別
2. isolation_read_uncommitted :這是事務最低的隔離級別,它充許別外乙個事務可以看到這個事務未提交的資料。這種隔離級別會產生髒讀,不可重複讀和幻像讀。
3. isolation_read_committed :保證乙個事務修改的資料提交後才能被另外乙個事務讀取。另外乙個事務不能讀取該事務未提交的資料。這種事務隔離級別可以避免髒讀出現,但是可能會出現不可重複讀和幻像讀。:
4. isolation_repeatable_read :這種事務隔離級別可以防止髒讀,不可重複讀。但是可能出現幻像讀。
5. isolation_serializable :這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。除了防止髒讀,不可重複讀外,還避免了幻讀。
spring學習筆記(九)事務學習(上)
這段時間在工作中碰到乙個事務相關的問題。先說下這個問題的場景,我們是乙個 專案,正在開發優惠券模組,現在有乙個需求是需要批量領取優惠券,而且在領券時,其中一張領取失敗不能影響其他符合要求的券的領取。由於之前在開發時,在領券這一塊一直做的是單張領取,所以在做批量的時候很簡單的做了個迴圈,然後封裝成乙個...
spring學習筆記九
為什麼要學習 模式?因為springaop的底層就是 模式的實現,而aop則是封裝了這些功能。模式的分類 我們可以看到,其實我們想要租房東的房子,但是我們並沒有直接呼叫房東的租房功能,而是通過中介,因為中介裡面封住了乙個租房方法,而這個租房方法其實是呼叫房東的方法。好處是為其他物件提供一種 以控制對...
Spring事務學習筆記(一)
事務是邏輯上的一組操作,這組操作要麼全部成功,要麼全部失敗。舉例 銀行系統a向b轉帳,分為兩個階段,第乙個階段從a賬戶中扣錢,第二個階段向b賬戶中轉錢,這就是乙個事務,需要保證只有這兩個階段都成功執行了才算整個事務成功執行,如果第乙個階段成功,第二個階段失敗,那麼事務也是失敗,需要回滾到這次事務開始...