[英]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.