I am currently testing a rather simple example concerning messaging transactions in connection with database transactions with spring amqp.
The use case is as follows:
- message is received
- a message is sent
database is updated
@Transactional public void handleMessage(EventPayload event) { MyEntity entity = new MyEntity(); entity.setName(event.getName()); rabbitTemplate.convertAndSend("myExchange", "payload.create", payload); MyEntity savedEntity = entityRepository.save(entity); }
The expected behavior in case of a failure during the database operation is that the received message is rolled back to the bus (DefaultRequeueRejected = false) and goes into a dead letter queue. Also the message sent should be rolled back.
I can achieve this with the following configuration:
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(messageConverter);
rabbitTemplate.setChannelTransacted(true);
return rabbitTemplate;
}
@Bean
SimpleMessageListenerContainer subscriberListenerContainer(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter,
PlatformTransactionManager transactionManager) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(SUBSCRIBER_QUEUE_NAME);
container.setMessageListener(listenerAdapter);
container.setChannelTransacted(true);
container.setTransactionManager(transactionManager);
container.setDefaultRequeueRejected(false);
return container;
}
So this works fine - what I do not understand is that the observed behavior is exactly the same if I do not set the transaction manager on the SimpleMessageListenerContainer
. So if I configure the following the bebavior does not change:
@Bean
SimpleMessageListenerContainer subscriberListenerContainer(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(SUBSCRIBER_QUEUE_NAME);
container.setMessageListener(listenerAdapter);
container.setDefaultRequeueRejected(false);
return container;
}
Can someone explain what is happening there? Why is the second case also working? What is different internally if the PlatformTransactionManager
is registered on the SimpleMessageListenerContainer
.