私はこのシナリオを持っています:
したがって、ステップ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" />
前もって感謝します。
Shyamの答えは正しかった。私はすでにこの問題に直面していました。これは問題ではなく、スプリング機能です。 「トランザクションはロールバック専用としてマークされているため、ロールバックされました」は受け入れ可能です。
結論
詳細を説明しましょう。
質問:トランザクションはいくつありますか?Anser:1つのみ
PROPAGATIONはPROPAGATION_REQUIREDに設定されているため、@ Transaction persist()はcaller-processNextRegistrationMessage()で同じトランザクションを使用しています。実際、例外が発生すると、SpringはTransactionManagerにrollBackOnlyを設定するため、Springは1つのトランザクションのみをロールバックします。
質問:()の外側にtry-catchがありますが、なぜこの例外が発生するのですか?一意のトランザクションのために答えてください
外の漁場に行く
Spring will set the rollBaclOnly to true -> it determine we must
rollback the caller (processNextRegistrationMessage) also.
Persist()は最初にそれ自体をロールバックします。
質問:なぜPROPAGATIONをREQUIRES_NEWに変更するのですか、それは機能しますか?
Anwser:processNextRegistrationMessage()とpersist()が異なるトランザクションにあるため、トランザクションのみをロールバックするようになりました。
ありがとう