Транзакция помечена только как откат: как найти причину
у меня возникли проблемы с фиксацией транзакции в моем @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()...
- контекст methodB полностью отсутствует в исключении - что нормально, я полагаю?
- что-то в methodB() помечено транзакцией только как откат? Как я могу это узнать? Есть например способ проверить что-то вроде
getCurrentTransaction().isRollbackOnly()?- как это я мог бы пройти через метод и найти причину.
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