SpringBoot事務註解@Transactional 事物回滾、手動回滾事物
處理springboot 下提交事務異常,資料庫沒有回滾的問題。
spring的文件中說道,spring宣告式事務管理預設對非檢查型異常和執行時異常進行事務回滾,而對檢查型異常則不進行回滾操作。
什麼是檢查型異常什麼又是非檢查型異常?
最簡單的判斷點有兩個:
1.繼承自runtimeexception或error的是非檢查型異常,而繼承自exception的則是檢查型異常(當然,runtimeexception本身也是exception的子類)。
2.對非檢查型類異常可以不用捕獲,而檢查型異常則必須用try語句塊進行處理或者把異常交給上級方法處理總之就是必須寫程式碼處理它。所以必須在service捕獲異常,然後再次丟擲,這樣事務方才起效。
結論:
在spring的事務管理環境下,使用unckecked exception可以極大地簡化異常的處理,只需要在事務層宣告可能丟擲的異常(這裡的異常可以是自定義的unckecked exception體系),在所有的中間層都只是需要簡單throws即可,不需要捕捉和處理,直接到最高層,比如UI層再進行異常的捕捉和處理。
預設規則:
1 讓checked例外也回滾: @Transactional(rollbackFor=Exception.class),一般只需新增這個即可
2 讓unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
3 不需要事務管理的(只查詢的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED),或者不新增
注意:如果異常被try{}catch{}了,事務就不回滾了,如果想讓事務回滾必須再往外拋try{}catch{throw Exception}。因為一旦你try{}catch{}了。系統會認為你已經手動處理了異常,就不會進行回滾操作。
示例:
1 @Override 2 @Transactional(rollbackFor = Exception.class) 3 public Integer submitOrder(FlashbuyOrder flashbuyOrder, List<FlashbuyOrderItem> itemList)示例4 throws Exception 5 { 6 7 return null; 8 9 }
spring 事務控制 設定手動回滾 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
https://www.cnblogs.com/liuzhenlei/p/6777644.html
1 //假設這是一個service類的片段 2 3 try{ 4 //出現異常 5 } catch (Exception e) { 6 e.printStackTrace(); 7 //設定手動回滾 8 TransactionAspectSupport.currentTransactionStatus() 9 .setRollbackOnly(); 10 } 11 //此時return語句能夠執行 12 return xxx;View Code
如上:
當我們需要在事務控制的service層類中使用try catch 去捕獲異常後,就會使事務控制失效,因為該類的異常並沒有丟擲,就不是觸發事務管理機制。怎樣才能即使用try catch去捕獲異常,而又讓出現異常後spring回滾呢,這裡就要用到
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
完美解決問題。並且能夠使該方法執行完。
這個需要注意兩點:
1. 方法上要加上 @Transactional(rollbackFor = Exception.class) 再配合TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 才可以,
否則會報錯NoTransactionException: No transaction aspect-managed TransactionStatus in scope
at
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ) public void testInsert(int index) throws Exception { OrderDO orderDO = new OrderDO(); orderDO.setThirdOrderId("1000"); int rowCount = this.orderMapper.insertOrder(orderDO); if (index == 1) { throw new RuntimeException("wrong"); } if (index == 2) { throw new Exception("wrong"); } if (index == 3) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }View Code
2. Spring Transactional一直是RD的事務神器,但是如果用不好,反會傷了自己。下面總結@Transactional經常遇到的幾個場景:
@Transactional 加於private方法, 無效
@Transactional 加於未加入介面的public方法, 再通過普通介面方法呼叫, 無效
@Transactional 加於介面方法, 無論下面呼叫的是private或public方法, 都有效
@Transactional 加於介面方法後, 被本類普通介面方法直接呼叫, 無效
@Transactional 加於介面方法後, 被本類普通介面方法通過介面呼叫, 有效
@Transactional 加於介面方法後, 被它類的介面方法呼叫, 有效
@Transactional 加於介面方法後, 被它類的私有方法呼叫後, 有效
View Code
Transactional是否生效, 僅取決於是否加載於介面方法, 並且是否通過介面方法呼叫(而不是本類呼叫)。
https://segmentfault.com/a/1190000014617571
ProductService.java /**********************************************************************/ public interface ProductService{ Integer getPrice(ProductInfo p); Integer compute(ProductInfo p); } /**********************************************************************/ ProductServiceImpl.java /**********************************************************************/ @Service public class ProductServiceImpl implements ProductService{ @Autowired private ProductService productService; public Integer getPrice(ProductInfo p){ productService.compute(p); } @Transactional(rollbackFor = Exception.class) public Integer compute(ProductInfo p){ try{ ... }catch(Exception e){ e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return 0; } } } 是可以的,因為是通過介面呼叫了View Code
ProductService.java /**********************************************************************/ public interface ProductService{ Integer getPrice(ProductInfo p); } public interface MyService{ Integer compute(ProductInfo p); } /**********************************************************************/ ProductServiceImpl.java /**********************************************************************/ @Service public class ProductServiceImpl implements ProductService{ @Autowired private MyService myService ; public Integer getPrice(ProductInfo p){ myService.compute(p); } } @Service public class MyServiceImpl implements MyService{ @Transactional(rollbackFor = Exception.class) public Integer compute(ProductInfo p){ try{ ... }catch(Exception e){ e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return 0; } } } 放在兩個介面類裡面,然後通過介面方法呼叫,是可以生效的View Code
3.在web專案中,很多時候要用到@Transactional 註解方法或者類進行事務處理,自動事務提交有時候就會有問題,這個時候就要用到手動進行事務提交 ,在try catch 異常丟擲裡面手動回滾事務處理TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
使用Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 設定回滾點,
使用TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);回滾到savePoint。
轉自:
https://blog.csdn.net/zhuchunyan_aijia/article/details/80191534
https://blog.csdn.net/xuhaogang3/article/details/82190026