1. 程式人生 > >UnexpectedRollbackException: Transaction rolled back 關於失誤自動回滾的問題

UnexpectedRollbackException: Transaction rolled back 關於失誤自動回滾的問題

完整的異常資訊:

 org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

字面意思:

        出現了不可預知的回滾異常,因為事務已經被標誌位只能回滾,所以事務回滾了。

解釋:

       以下邊程式碼舉例

class ServiceA{


//傳播屬性設定為PROPAGATION_REQUIRED

void methodA(){

try{

serviceB.methodB();

}catch (Exception e){


}

}



}


class ServiceB{


//傳播屬性設定為PROPAGATION_REQUIRED

void methodB(){


}

因為methodB的傳播屬性設定為PROPAGATION_REQUIRED,PROPAGATION_REQUIRED的意思是,當前有事務,則使用當前事務,當前無事務則建立事務。由於methodA的傳播屬性也為PROPAGATION_REQUIRED,所以methodA會建立一個事務,然後methodB與methodA使用同一個事務,methodB出現異常後,將當前事務標誌位回滾,由於在methodA中做了trycatch處理,程式沒有終止而是繼續往下走,當事務commit時,check狀態,發現,需要事務回滾,所以才會出現不可預知的事務異常:因為事務被標誌位回滾,所以事務回滾。

一言以概之,methodA與methodB共用一個事務,methodB將事務標誌為回滾,methodA中commit這個事務,然後,出現事務已經被標誌回滾(methodB標誌的)的異常資訊。

修改:

情況1:methodA與methodB在邏輯上不應該屬於同一個事務,那麼將methodB的事務傳播屬性修改為PROPAGATION_REQUIRES_NEW,這樣,執行methodB時,會建立一個新的事務,不影響methodA中的事務。

情況2:業務A與業務B在業務邏輯上就應該屬於同一個事務,那麼將methodA中的try  catch去掉

情況3:業務A與業務B在業務邏輯上就應該屬於同一個事務,但是methodB的失敗與否不能影響methodA的事務提交,那麼仍然在methodA中try catch methodB,並將methodB設定為PROPAGATION_NESTED,它的意思是,methodB是一個子事務,有一個savepoint,失敗時會回滾到savepoint,不影響methodA,如果成功則A、B一起提交,A與B都是一個事務,只是B是一個子事務

總結:

1、深入理解事務傳播的各個狀態含義,比如PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY、PROPAGATION_REQUIRES_NEW等

2、最初我以為是由於spring配置檔案中,methodA的事務設定為ready-only=true(只讀事務)的原因,經過查詢資料得知,只讀事務與事務傳播不衝突,是兩個機制。只讀事務,是一個特殊的事務,該事務內,只能是查詢語句,不能含有修改、更新語句,資料庫可能對只讀事務做優化;傳播屬性是母方法與子方法之間的關係表達。

3、注意,同一個類中,事務巢狀以最外層的方法為準,巢狀的事務失效;不同類中巢狀的事務才會生效;