gpt4 book ai didi

java - 意外回滚异常 : Transaction rolled back because it has been marked as rollback-only

转载 作者:IT老高 更新时间:2023-10-28 13:44:54 27 4
gpt4 key购买 nike

我有这种情况:

  1. IncomingMessage 表中获取(读取和删除)一条记录
  2. 读取记录内容
  3. 在一些表格中插入一些东西
  4. 如果在步骤 1-3 中发生错误(任何异常),请在 OutgoingMessage 表中插入错误记录
  5. 否则,在 OutgoingMessage 表中插入一条成功记录

所以步骤 1,2,3,4 应该在事务中,或者步骤 1,2,3,5

我的流程从这里开始(这是一个计划任务):

public class ReceiveMessagesJob implements ScheduledJob {
// ...
@Override
public void run() {
try {
processMessageMediator.processNextRegistrationMessage();
} catch (Exception e) {
e.printStackTrace();
}
}
// ...
}

我在ProcessMessageMediator中的主要功能(processNextRegistrationMessage):

public class ProcessMessageMediatorImpl implements ProcessMessageMediator {
// ...
@Override
@Transactional
public void processNextRegistrationMessage() throws ProcessIncomingMessageException {
String refrenceId = null;
MessageTypeEnum registrationMessageType = MessageTypeEnum.REGISTRATION;
try {
String messageContent = incomingMessageService.fetchNextMessageContent(registrationMessageType);
if (messageContent == null) {
return;
}
IncomingXmlModel incomingXmlModel = incomingXmlDeserializer.fromXml(messageContent);
refrenceId = incomingXmlModel.getRefrenceId();
if (!StringUtil.hasText(refrenceId)) {
throw new ProcessIncomingMessageException(
"Can not proceed processing incoming-message. refrence-code field is null.");
}
sqlCommandHandlerService.persist(incomingXmlModel);
} catch (Exception e) {
if (e instanceof ProcessIncomingMessageException) {
throw (ProcessIncomingMessageException) e;
}
e.printStackTrace();
// send error outgoing-message
OutgoingXmlModel outgoingXmlModel = new OutgoingXmlModel(refrenceId,
ProcessResultStateEnum.FAILED.getCode(), e.getMessage());
saveOutgoingMessage(outgoingXmlModel, registrationMessageType);
return;
}
// send success outgoing-message
OutgoingXmlModel outgoingXmlModel = new OutgoingXmlModel(refrenceId, ProcessResultStateEnum.SUCCEED.getCode());
saveOutgoingMessage(outgoingXmlModel, registrationMessageType);
}

private void saveOutgoingMessage(OutgoingXmlModel outgoingXmlModel, MessageTypeEnum messageType)
throws ProcessIncomingMessageException {
String xml = outgoingXmlSerializer.toXml(outgoingXmlModel, messageType);
OutgoingMessageEntity entity = new OutgoingMessageEntity(messageType.getCode(), new Date());
try {
outgoingMessageService.save(entity, xml);
} catch (SaveOutgoingMessageException e) {
throw new ProcessIncomingMessageException("Can not proceed processing incoming-message.", e);
}
}
// ...
}

正如我所说,如果在步骤 1-3 中发生任何异常,我想插入一条错误记录:

catch (Exception e) {
if (e instanceof ProcessIncomingMessageException) {
throw (ProcessIncomingMessageException) e;
}
e.printStackTrace();
//send error outgoing-message
OutgoingXmlModel outgoingXmlModel = new OutgoingXmlModel(refrenceId,ProcessResultStateEnum.FAILED.getCode(), e.getMessage());
saveOutgoingMessage(outgoingXmlModel, registrationMessageType);
return;
}

是SqlCommandHandlerServiceImpl.persist()方法:

public class SqlCommandHandlerServiceImpl implements SqlCommandHandlerService {
// ...
@Override
@Transactional
public void persist(IncomingXmlModel incomingXmlModel) {
Collections.sort(incomingXmlModel.getTables());
List<ParametricQuery> queries = generateSqlQueries(incomingXmlModel.getTables());
for (ParametricQuery query : queries) {
queryExecuter.executeQuery(query);
}
}
// ...
}

但是当 sqlCommandHandlerService.persist() 抛出异常(这里是 org.hibernate.exception.ConstraintViolationException 异常),在 OutgoingMessage 表中插入错误记录后,当要提交事务时,我得到 UnexpectedRollbackException。 我不知道我的问题出在哪里:

Exception in thread "null#0" org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:717)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:394)
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 ir.tamin.branch.insuranceregistration.services.schedular.ReceiveMessagesJob$$EnhancerByCGLIB$$63524c6b.run(<generated>)
at ir.asta.wise.core.util.timer.JobScheduler$ScheduledJobThread.run(JobScheduler.java:132)

我正在使用 hibernate-4.1.0-Final,我的数据库是 oracle,这是我的事务管理器 bean:

<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager"
proxy-target-class="true" />

提前致谢。

最佳答案

这是正常行为,原因是您的 sqlCommandHandlerService.persist 方法在执行时需要一个 TX(因为它标有 @Transactional 注释)。但是当它在processNextRegistrationMessage中被调用时,因为有一个可用的TX,容器不会创建一个新的,而是使用现有的TX。因此,如果 sqlCommandHandlerService.persist 方法中发生任何异常,它会导致 TX 设置为 rollBackOnly(即使您在调用者中捕获了异常并忽略它)。

要克服这个问题,您可以对事务使用传播级别。看看this找出最适合您要求的传播方式。

更新;阅读本文!

在一位同事向我提出了一些关于类似情况的问题之后,我觉得这需要澄清一下。
尽管传播解决了此类问题,但您应该非常小心使用它们,除非您绝对了解它们的含义以及它们的工作原理,否则不要使用它们。您最终可能会保留一些数据并回滚其他一些您不希望它们以这种方式工作的数据,并且可能会出现严重错误。


编辑 Link to current version of the documentation

关于java - 意外回滚异常 : Transaction rolled back because it has been marked as rollback-only,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19349898/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com