• 解决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也是这样的。而我只是在外面捕捉了这个异常,所以发生的这样的问题。

  • 相关阅读:
    第十九节 集群模式内各节点的通信和文件拷贝
    第十八节 虚拟机克隆后ip修改
    WAF 与 RASP 的安装使用大比拼!
    不改变中间层,如何玩转 .NET 的远程处理功能?
    什么是实时应用程序自我保护(RASP)?
    拒绝「技术栈」选择恐惧症
    为什么Nagios会那么吵?你又能做些什么呢?(1)
    Java 应用发布后,需要关注的7个性能指标
    玩转AWS CloudWatch微信告警
    日均百万 PV 的站点如何做性能监测?试试「3M口罩」!
  • 原文地址:https://www.cnblogs.com/fashflying/p/5669228.html
Copyright © 2020-2023  润新知