[java] 롤백으로 만 표시된 트랜잭션 : 원인을 어떻게 찾습니까?

내 @Transactional 메서드 내에서 트랜잭션을 커밋하는 데 문제가 있습니다.

methodA() {
    methodB()
}

@Transactional
methodB() {
    ...
    em.persist();
    ...
    em.flush();
    log("OK");
}

methodA ()에서 methodB ()를 호출하면 메서드가 성공적으로 전달되고 로그에 “OK”가 표시됩니다. 하지만 나는

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)
    at methodA()...
  1. methodB의 컨텍스트는 예외에서 완전히 누락되어 있습니다.
  2. methodB () 내의 무언가가 트랜잭션을 롤백으로 만 표시 했습니까? 어떻게 알 수 있습니까? 예를 들어 다음과 같은 것을 확인하는 방법이 있습니까 getCurrentTransaction().isRollbackOnly()?-이와 같이 방법을 단계별로 수행하고 원인을 찾을 수 있습니다.



답변

당신은 귀하의 방법을 표시하면 @Transactional, 당신의 방법 내부 예외의 발생은 롤백 전용 (당신이 그들을 잡을 경우에도)로 주변 TX를 표시합니다. @Transactional주석의 다른 속성을 사용 하여 다음과 같은 롤백을 방지 할 수 있습니다 .

@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)


답변

마침내 문제를 이해했습니다.

methodA() {
    methodB()
}

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

@Transactional
methodC() {
    throw new ...();
}

무슨 일이 일어나는 methodB가는에 올바른 주석이 있어도 methodC그렇지 않다는 것입니다. 예외가 발생하면 두 번째 @Transactional는 첫 번째 트랜잭션을 어쨌든 롤백으로 만 표시합니다.


답변

다시 코딩하거나 다시 빌드 할 필요없이 원인이되는 예외를 빠르게 가져 오려면 중단 점을

org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3

스택에서 보통 인터셉터로 올라갑니다. 거기에서 일부 catch 블록에서 발생하는 예외를 읽을 수 있습니다.


답변

내 응용 프로그램을 실행하는 동안이 예외로 고생했습니다.

마지막으로 문제는 SQL 쿼리에있었습니다. 있었습니다. 나는 쿼리가 잘못되었음을 의미합니다.

쿼리를 확인하십시오. 이것은 내 제안입니다


답변

던져지고 잡히는 예외를 찾으십시오. ...코드 섹션 . 런타임 및 롤백 애플리케이션 예외로 인해 다른 장소에서 발견 된 경우에도 비즈니스 메소드에서 폐기 될 때 롤백이 발생합니다.

컨텍스트를 사용하여 트랜잭션이 롤백으로 표시되었는지 여부를 확인할 수 있습니다.

@Resource
private SessionContext context;

context.getRollbackOnly();


답변

솔루션으로 좋은 설명을 찾았습니다 : https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/

1) 실제로 트랜잭션 제어가 필요하지 않은 경우 중첩 된 메서드에서 @Transacional을 제거합니다. 따라서 예외가 있어도 거품이 발생하고 트랜잭션에 영향을 미치지 않습니다.

또는:

2) 중첩 된 메서드에 트랜잭션 제어가 필요한 경우 전파 정책에 대해 REQUIRE_NEW로 설정하여 예외를 throw하고 롤백 전용으로 표시하더라도 호출자에게 영향을주지 않습니다.


답변

Bean.xml에서 transactionmanager를 비활성화하십시오.

<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

이 줄을 주석 처리하면 롤백을 유발하는 예외가 표시됩니다.)