簡體   English   中英

帶有 AOP @AfterReturning 的 Spring 中出現 UnexpectedRollbackException

[英]UnexpectedRollbackException in Spring with AOP @AfterReturning

我已經使用 Spring AOP 為每個保存操作設置了日志記錄,我在其中標記了@Transactional 問題是當我的保存方法拋出異常並僅用回滾標記事務時,但使用 AOP 的日志記錄操作不知道。 這就是為什么它導致:

'事務靜默回滾,因為它已被標記為僅回滾'。

如何克服這種情況?

我的保存方法:

@Transactional
public void create(SecModuleRequest secModuleRequest) {
  SecModule secModule = secModuleRepository.save(pData); // throw data integrity exception
}

我的記錄方法:

@Transactional
@AfterReturning(value = "execution(public * save(..)) && this(org.springframework.data.repository.CrudRepository)", returning = "responseEntity")
public void onSaveExecuted(JoinPoint pjp, Object responseEntity) {
    try {            
        ...            
        insertAuditLog(jsonStr, entityActionLog.getQueryClauseExt());
    } catch (Exception ex) {
      ex.printStackTrace();
    }
}

public int insertAuditLog(String auditContent, String queryRowId) {
    String sql = " Insert into LOG (LOG_ID,LOG_DATETIME, LOG_CONTENT) " +
            "           values (LOG_SEQ.NEXTVAL, SYSDATE, ?) ";
    Query query = entityManager.createNativeQuery(sql);
    query.setParameter(1, auditContent);        
    int resultInsert = query.executeUpdate();
    return resultInsert;
}

我認為這里的方法調用順序如下

方法create()啟動事務並調用方法secModuleRepository.save(pData)

假設secModuleRepository.save(pData)具有默認的事務傳播REQUIRED ,它會參與使用方法create()開始的事務。

save()毫無例外地返回,並由@AfterReturning建議方法onSaveExecuted()提供建議。

提交事務時,此事務將導致DataIntegrityViolationException 這發生在該事務結束時,即控件退出方法create()時。

要記錄所有情況下的save()方法調用,建議類型應該是@After@Around並且日志調用不應該是可以在提交時回滾的事務的一部分。

以下代碼使用TransactionTemplate啟動新事務並插入日志。 這個想法是要記錄一個新事務,並且給出的示例代碼重用與問題共享的代碼,可以根據要求進行改進。

@Aspect
@Component
public class TxnAspect {

    @PersistenceContext
    private EntityManager entityManager;

    // single TransactionTemplate shared amongst all methods in this instance
    private final TransactionTemplate transactionTemplate;

    // use constructor-injection to supply the PlatformTransactionManager
    public TxnAspect(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }

    @Around(value = "execution(public * save(..)) && this(org.springframework.data.jpa.repository.JpaRepository)")
    public Object onSaveExecuted(ProceedingJoinPoint pjp) throws Throwable {
        Object responseEntity = null;
        try {
            responseEntity = pjp.proceed();
        } finally {
            //gather the details and log
            executeInNewTxn("log1","log2");
        }
        return responseEntity;
    }

    public Object executeInNewTxn(String str1, String str2) {
        transactionTemplate.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
        return transactionTemplate.execute(new TransactionCallback<Object>() {
            // the code in this method executes in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                return insertAuditLog(str1, str2);
            }
        });
    }

    public int insertAuditLog(String auditContent, String queryRowId) {
        String sql = " Insert into LOG (LOG_ID,LOG_DATETIME, LOG_CONTENT) "
                + "           values (100, SYSDATE, ?) ";
        Query query = entityManager.createNativeQuery(sql);
        query.setParameter(1, auditContent);
        int resultInsert = query.executeUpdate();
        return resultInsert;
    }
}

希望這可以幫助

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM