解決Could not commit JPA transaction RollbackException: Transaction marked as rollbackOnly


項目測試發生問題,方法正常結束,但是報了

Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)

錯誤,問什么不能提交呢?

經過查找發現了這么一段話

I finally understood the problem:

methodA() {
    methodB()
}

@Transactional(noRollbackFor = Exception.class)
methodB() {
    ...
    try {
        methodC()
    } catch (...) {...}
    log("OK");
}

@Transactional
methodC() {
    throw new ...();
}
What happens is that even though the methodB has the right annotation, the methodC does not. When the exception is thrown, the second @Transactional marks the first transaction as Rollback only anyway.

原來,在一個transactional中如果有另一transaction發生了異常,即使你捕捉了這個異常,那么Transaction也會被定義成RollbackOnly,這也正是事務管理的原則,可是我的系統哪里出異常了呢?

原來,spring jpa JpaRepository的實現方法中用ID刪除的源碼是這樣的

@Transactional
    public void delete(ID id) {

        Assert.notNull(id, ID_MUST_NOT_BE_NULL);

        T entity = findOne(id);

        if (entity == null) {
            throw new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!",
                    entityInformation.getJavaType(), id), 1);
        }

        delete(entity);
    }

他是這樣實現的,先查找這個ID的對象看是否存在如果不存在則直接拋出一個非檢查型異常,就不再執行delete操作。這和我平常習慣認為的不太一樣,一般我習慣刪除沒有的記錄不會報錯,執行sql也是這樣的。而我只是在外面捕捉了這個異常,所以發生的這樣的問題。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM