2016-12-07 2 views
2

Ainsi, la configuration est le suivant:intégration Spring et JDBC dans seule transaction

<tx:advice id="txAdvice2" transaction-manager="dataSourceTransactionManager"> 
    <tx:attributes> 
     <tx:method name="*" rollback-for="Throwable" no-rollback-for="ListenerExecutionFailedException"/> 
    </tx:attributes> 
</tx:advice> 

<int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter" 
            channel-transacted="true" 
            advice-chain="txAdvice2" /> 

<int:chain input-channel="input-channel" output-channel="output-channel"> 
    <int:service-activator ref="h1Handler" method="handle" /> 
    <int:service-activator ref="h2Handler" method="handle" /> 
    <int:service-activator ref="h3Handler" method="handle" /> 
    <int:splitter /> 
</int:chain> 

<int-amqp:outbound-channel-adapter channel="output-channel" exchange-name="outputit" amqp-template="rabbitTemplate" /> 

Si lors de l'exécution de ce fil (puisque toute cette chaîne amqpIN-processus amqpOUT shold exécuter dans seul thread) Je jette ListenerExecutionFailedException, dataSourceTransactionManager effectuera la validation, mais amqp remettra également le message en attente, car l'exception est propagée.

Comment puis-je dire à lapin ACK que le message a réussi dans ce cas?

En outre, j'ai vu que je devais mettre dans no-rollback-for attribut exception réelle classe, puisque mon-exception interne est seulement stockée dans l'attribut "cause" qui n'est pas inspecté par le RuleBasedTransactionAttribute.

une chose, si je fais config comme ceci:

<int-amqp:inbound-channel-adapter channel="input-channel" queue-names="probni" message-converter="jsonMessageConverter" 
            channel-transacted="true" 
            transaction-manager="dataSourceTransactionManager" 
            transaction-attribute="transactionAttribute" /> 

TransactionAttribute qui est RuleBasedTransactionAttribute n'est pas considéré du tout et dataSourceTransactionManager est toujours rollbacked même si je n'ai pas-rollback pour régler correctement.

Merci!

Répondre

2

Vous pouvez ajouter une commande ErrorHandler au conteneur d'écoute ( vous devez configurer le conteneur externe et fournir une référence dans le container attribut ).

Le gestionnaire d'erreurs par défaut est un ConditionalRejectingErrorHandler avec un DefaultExceptionStrategy qui prend en compte certaines exceptions de cause LEFE comme fatale:

private boolean isCauseFatal(Throwable cause) { 
     return cause instanceof MessageConversionException 
       || cause instanceof org.springframework.messaging.converter.MessageConversionException 
       || cause instanceof MethodArgumentNotValidException 
       || cause instanceof MethodArgumentTypeMismatchException 
       || cause instanceof NoSuchMethodException 
       || cause instanceof ClassCastException 
       || isUserCauseFatal(cause); 
    } 

À partir de la version 1.6.4, vous pouvez sous-classe par défaut DefaultExceptionStrategy et ajoutez votre cause (s) à isUserCauseFatal(). Avant la version 1.6.4, vous deviez fournir votre propre FatalExceptionStrategy (ou l'implémentation du gestionnaire d'erreurs).

Pour les causes fatales, le gestionnaire lance un AmqpRejectAndDontRequeueException qui indique au conteneur de nouer (et de ne pas remettre en file d'attente) le message.

EDIT

Par ailleurs, il n'y a pas besoin de vous envelopper l'exception, le conteneur fera pour vous ...

protected Exception wrapToListenerExecutionFailedExceptionIfNeeded(Exception e, Message message) { 
    if (!(e instanceof ListenerExecutionFailedException)) { 
     // Wrap exception to ListenerExecutionFailedException. 
     return new ListenerExecutionFailedException("Listener threw exception", e, message); 
    } 
    return e; 
} 

EDIT2

Mon erreur, le ErrorHandler peut être spécifié en utilisant l'attribut error-handler.

EDIT3

Sinon, il suffit de jeter un AmqpRejectAndDontRequeueException (qui sera wrapped LEFE).

+0

Vous n'avez pas besoin d'envelopper l'exception; voir mon edit. En outre, vous pouvez utiliser l'attribut 'error-handler'. –

+0

Merci pour la réponse rapide. Je vais essayer ça demain.Si je rejetteAndDontRequeue - cela finira-t-il dans DeadLetterQueue? Je voudrais que ceci soit traité comme ACK ordinaire, puisque je veux faire ceci dans le cas où ce message est remis (livré au moins une fois + peut-être plus). Savez-vous aussi, en passant, pourquoi l'attribut de transaction ne fonctionne pas sur la transaction lorsqu'il est fourni à l'intérieur d'un canal d'entrée-de-canal, mais fonctionne s'il est utilisé comme conseil? (La deuxième partie de la question). –

+0

Si le message est réémis mais que jdbc est déjà validé, je veux lancer une exception qui annulera le message jdbc mais ack rabbit (puisque je commet et acquitte à la fin du pipeline de traitement). –