摘要:在嵌套事務場景中,內層事務的和外層事務的會在外層事務結束時進行提交或回滾。解決方案如果希望內層事務拋出異常時中斷程序執行,直接在外層事務的代碼塊中拋出如果希望程序正常執行完畢,并且希望外層事務結束時全部提交,需要在內層事務中做異常捕獲處理。
前言
最近在項目中發現了一則報錯:“org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only”。根據報錯信息來看是spring框架中的事務管理報錯:事務回滾了,因為它被標記為回滾狀態。
報錯原因多層嵌套事務中,如果使用了默認的事務傳播方式,當內層事務拋出異常,外層事務捕捉并正常執行完畢時,就會報出rollback-only異常。
spring框架是使用AOP的方式來管理事務,如果一個被事務管理的方法正常執行完畢,方法結束時spring會將方法中的sql進行提交。如果方法執行過程中出現異常,則回滾。spring框架的默認事務傳播方式是PROPAGATION_REQUIRED:如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。
在項目中,一般我們都會使用默認的傳播方式,這樣無論外層事務和內層事務任何一個出現異常,那么所有的sql都不會執行。在嵌套事務場景中,內層事務的sql和外層事務的sql會在外層事務結束時進行提交或回滾。如果內層事務拋出異常e,在內層事務結束時,spring會把事務標記為“rollback-only”。這時如果外層事務捕捉了異常e,那么外層事務方法還會繼續執行代碼,直到外層事務也結束時,spring發現事務已經被標記為“rollback-only”,但方法卻正常執行完畢了,這時spring就會拋出“org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only”。
代碼示例如下:
Class ServiceA { @Resource(name = "serviceB") private ServiceB b; @Transactional public void a() { try { b.b() } catch (Exception ignore) { } } } Class ServiceB { @Transactional public void b() { throw new RuntimeException(); } }
當調用a()時,就會報出“rollback-only”異常。
解決方案如果希望內層事務拋出異常時中斷程序執行,直接在外層事務的catch代碼塊中拋出e.
如果希望程序正常執行完畢,并且希望外層事務結束時全部提交,需要在內層事務中做異常捕獲處理。
如果希望內層事務回滾,但不影響外層事務提交,需要將內層事務的傳播方式指定為PROPAGATION_NESTED。注:PROPAGATION_NESTED基于數據庫savepoint實現的嵌套事務,外層事務的提交和回滾能夠控制嵌內層事務,而內層事務報錯時,可以返回原始savepoint,外層事務可以繼續提交。
在我的項目中之所以會報“rollback-only”異常的根本原因是代碼風格不一致的原因。外層事務對錯誤的處理方式是返回true或false來告訴上游執行結果,而內層事務是通過拋出異常來告訴上游(這里指外層事務)執行結果,這種差異就導致了“rollback-only”異常。雖然最后事務依然是回滾了,不影響程序對sql的處理,但外層事務的上游本期望返回true和false,卻收到了UnexpectedRollbackException異常,(╯ ̄Д ̄)╯︵ ┻━┻。
附:事務傳播方式@see org.springframework.transaction.annotation.Propagation
事務傳播方式 | 說明 |
---|---|
PROPAGATION_REQUIRED | 如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。這是默認的傳播方式 |
PROPAGATION_SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行 |
PROPAGATION_MANDATORY | 使用當前的事務,如果當前沒有事務,就拋出異常 |
PROPAGATION_REQUIRES_NEW | 新建事務,如果當前存在事務,把當前事務掛起 |
PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起 |
PROPAGATION_NEVER | 以非事務方式執行,如果當前存在事務,則拋出異常 |
PROPAGATION_SUPPORTS | 支持當前事務,如果當前沒有事務,就以非事務方式執行。 |
PROPAGATION_NESTED | 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77135.html
摘要:題目假設高度已知,請寫出三欄布局,其中左欄右欄寬度各為,中間自適應三欄布局的種方案這是一道經典的面試題,下面記錄了布局的種方法。 題目:假設高度已知,請寫出三欄布局,其中左欄、右欄寬度各為300px,中間自適應. 三欄布局的5種方案 這是一道經典的面試題,下面記錄了css布局的5種方法。 三欄布局 * { margin: 0; ...
摘要:前言三欄布局,顧名思義就是兩邊固定,中間自適應。三欄布局在實際的開發十分常見,比如淘寶網的首頁,就是個典型的三欄布局即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬度自適應。但網格布局的兼容性不好。 前言 三欄布局,顧名思義就是兩邊固定,中間自適應。三欄布局在實際的開發十分常見,比如淘寶網的首頁,就是個典型的三欄布局:即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬...
摘要:前言三欄布局,顧名思義就是兩邊固定,中間自適應。三欄布局在實際的開發十分常見,比如淘寶網的首頁,就是個典型的三欄布局即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬度自適應。但網格布局的兼容性不好。 前言 三欄布局,顧名思義就是兩邊固定,中間自適應。三欄布局在實際的開發十分常見,比如淘寶網的首頁,就是個典型的三欄布局:即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬...
摘要:前言三欄布局,顧名思義就是兩邊固定,中間自適應。三欄布局在實際的開發十分常見,比如淘寶網的首頁,就是個典型的三欄布局即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬度自適應。但網格布局的兼容性不好。 前言 三欄布局,顧名思義就是兩邊固定,中間自適應。三欄布局在實際的開發十分常見,比如淘寶網的首頁,就是個典型的三欄布局:即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬...
閱讀 694·2021-11-15 11:37
閱讀 3316·2021-10-27 14:14
閱讀 6038·2021-09-13 10:30
閱讀 2960·2021-09-04 16:48
閱讀 1926·2021-08-18 10:22
閱讀 2125·2019-08-30 14:19
閱讀 728·2019-08-30 10:54
閱讀 1744·2019-08-29 18:40