Транзакция помечена только как откат: как найти причину



у меня возникли проблемы с фиксацией транзакции в моем @Transactional методе:



methodA() {
methodB()
}

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


когда я вызываю methodB () из methodA (), метод успешно проходит, и я вижу "ОК" в своих журналах. Но тогда я получаю



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()? - как это я мог бы пройти через метод и найти причину.

3974   7  

7 ответов:

когда вы отмечаете свой способ как @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();

отключите transactionmanager в вашем компоненте.xml

<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>

закомментируйте эти строки, и вы увидите исключение, вызывающее откат ;)

нашел хорошее объяснение с решениями: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/

1) Удалите @Transacional из вложенного метода, если он действительно не требует управления транзакциями. Так что даже у него есть исключение, он просто пузырится и не влияет на транзакционные вещи.

или:

2) Если вложенный метод требует управления транзакциями, сделайте его как REQUIRE_NEW для политики распространения, которая способ даже если выбрасывает исключение и помечается только как откат, вызывающий объект не будет затронут.

Comments

    Ничего не найдено.