动态

详情 返回 返回

Transaction rolled back because marked as rollback-only問題解決 - 动态 详情

1、背景

在我們的日常開發中,經常會存在在一個Service層中調用另外一個Service層的方法。比如:我們有一個TaskService,裏面有一個execTask方法,且這個方法存在事務,這個方法在執行完之後,需要調用LogService的insertLog方法記錄一條日誌,這個方法上也有事務,不管日誌記錄成功還是失敗,都不能影響execTask方法的執行。因此我們很容易寫出如下代碼。

@Transactional
public void execTaskV1(){
    log.info("開始執行任務");
    try {
        logService.insertLogV1();
    } catch (Exception e) {
        log.error("添加日誌出現錯誤");
    }
    log.info("完成任務執行");
}

思考: 上方的代碼,如果insertLogV1跑出了異常,execTaskV1方法的事務可以正常提交嗎?

2、異常是如何實現出現的

1、瞭解Spring事務的傳播屬性

傳播行為 描述 應用場景 行為特點
Propagation.REQUIRED 如果當前存在事務,則加入該事務;如果當前沒有事務,則啓動一個新的事務。 大多數場景,如多個方法需要在同一個事務中完成。 - 如果當前事務存在,方法執行在當前事務上下文中。
- 如果當前事務不存在,創建新事務。
Propagation.SUPPORTS 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務方式執行。 對事務支持沒有強制要求的場景,如只讀查詢。 - 如果當前事務存在,方法執行在當前事務上下文中。
- 如果當前事務不存在,以非事務方式執行。
Propagation.MANDATORY 如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。 必須在一個已存在的事務中執行的場景。 - 必須在已有事務中執行,否則拋出 IllegalTransactionStateException
Propagation.REQUIRES_NEW 每次調用該方法時都會啓動一個新的事務。當前事務(如果有)會被掛起。 需要獨立事務的場景,如日誌記錄或獨立的業務操作。 - 總是創建新事務。
- 當前事務(如果有)會被掛起,直到新事務完成。
Propagation.NOT_SUPPORTED 總是以非事務方式執行,並且暫停當前事務(如果有)。 不需要事務的場景,如簡單的查詢操作。 - 總是以非事務方式執行。
- 暫停當前事務(如果有)。
Propagation.NEVER 總是以非事務方式執行,如果當前存在事務,則拋出異常。 嚴格禁止事務的場景,如某些非事務性操作。 - 必須在非事務上下文中執行,否則拋出 TransactionException
Propagation.NESTED 如果當前存在事務,則在嵌套事務內執行;如果當前沒有事務,則啓動一個新的事務。 需要嵌套事務的場景,如複雜的業務流程中需要獨立的回滾點。 - 如果當前事務存在,創建一個嵌套事務(依賴於數據庫支持)。
- 如果當前事務不存在,創建新事務。

2、模擬異常出現

Transaction rolled back because it has been marked as rollback-only 這個異常在上述的案例中是如何實現的呢?

從上圖中可知,出現了Transaction rolled back because it has been marked as rollback-only這個異常,那麼這個異常是如何出現的呢?

其實這個是和Spring事務的傳播屬性Propagation有關。

默認情況下@Transaction的傳播屬性是Propagation.REQUIRED, 即如果當前存在事務,則加入該事務;如果當前沒有事務,則啓動一個新的事務。 在我們的例子中,事務的隔離級別都是Propagation.REQUIRED,即是在同一個事務中,因此insertLogV1方法拋出異常後,雖然上層捕獲到了,但其實這個時候這個事務已經被標記成回滾狀態了,因此事務無法提交成功。

如何解決: 只需要修改insertLogV1事務的傳播屬性為Propagation.REQUIRES_NEW即可。

3、完整代碼

完整代碼-https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-transaction-v1

Add a new 评论

Some HTML is okay.