Транзакция, отмеченная только как откат: как мне найти причину
У меня возникают проблемы с совершением транзакции в моем методе @Transactional:
methodA() {
methodB()
}
@Transactional
methodB() {
...
em.persist();
...
em.flush();
log("OK");
}
Когда я вызываю методB() из метода A(), метод успешно проходит, и я могу видеть "ОК" в моих журналах. Но затем я получаю
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()...
- Контекст метода B полностью отсутствует в исключении - что, я полагаю, это нормально?
- Что-то в методе B() отметило транзакцию только как откат? Как я могу это узнать? Есть, например, способ проверить что-то вроде
getCurrentTransaction().isRollbackOnly()?
- вот так я мог бы пройти через этот метод и найти причину.
Ответы
Ответ 1
Наконец я понял проблему:
methodA() {
methodB()
}
@Transactional(noRollbackFor = Exception.class)
methodB() {
...
try {
methodC()
} catch (...) {...}
log("OK");
}
@Transactional
methodC() {
throw new ...();
}
Случается, что даже если methodB
имеет правильную аннотацию, methodC
нет. Когда исключение выбрасывается, второй @Transactional
в любом случае отмечает первую транзакцию как откат.
Ответ 2
Когда вы помечаете свой метод как @Transactional
, появление любого исключения внутри вашего метода будет отмечать окружающий TX только как откат (даже если вы их поймаете). Вы можете использовать другие атрибуты аннотации @Transactional
, чтобы предотвратить ее откат как:
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
Ответ 3
Чтобы быстро получить вызывающее исключение без необходимости повторного кодирования или перестройки, установите точку останова на
org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3
и поднимитесь в стек, как правило, на некоторый Interceptor. Там вы можете прочитать вызывающее исключение из некоторого блока catch.
Ответ 4
Я столкнулся с этим исключением при запуске приложения.
Наконец проблема была в запросе sql. Я имею в виду, что запрос неверен.
пожалуйста, подтвердите свой запрос. Это мое предложение
Ответ 5
Ищите исключения, которые бросаются и попадают в разделы ...
вашего кода. Исключения приложений и отката приложений вызывают откат при выкидывании из бизнес-метода, даже если он попадает в другое место.
Вы можете использовать контекст, чтобы узнать, отмечена ли транзакция для отката.
@Resource
private SessionContext context;
context.getRollbackOnly();
Ответ 6
отключите оператора транзакций в Bean.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>
прокомментируйте эти строки, и вы увидите исключение, вызывающее откат;)
Ответ 7
Нашел хорошее объяснение с решениями: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1) удалите @Transacional из вложенного метода, если он действительно не требует управления транзакциями. Так что даже у него есть исключение, оно просто пузырится и не влияет на транзакционные вещи.
ИЛИ ЖЕ:
2) если вложенному методу нужен контроль транзакций, сделайте его REQUIRE_NEW для политики распространения таким образом, даже если выдает исключение и помечает только как откат, на вызывающего это не повлияет.
Ответ 8
пожалуйста, проверьте ваш @Transactional импорт, он должен быть
import javax.transaction.Transactional;
Ответ 9
применить приведенный ниже код в productRepository
@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);
в то время как в тесте junit применяется ниже код
@Test
public void updateData()
{
int i=productRepository.updateMyData("Iphone",102);
System.out.println("successfully updated ... ");
assertTrue(i!=0);
}
это работает нормально для моего кода