繁体   English   中英

spring-amqp事务语义

[英]spring-amqp transaction semantics

我目前正在测试一个关于与spring amqp的数据库事务相关的消息传递事务的一个相当简单的例子。

用例如下:

  • 收到消息
  • 发送消息
  • 数据库已更新

     @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); } 

在数据库操作期间发生故障时的预期行为是收到的消息回滚到总线(DefaultRequeueRejected = false)并进入死信队列。 发送的消息也应该回滚。

我可以通过以下配置实现此目的:

@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;
    }

所以这很好 - 我不明白的是,如果我没有在SimpleMessageListenerContainer上设置事务管理器,观察到的行为是完全相同的。 因此,如果我配置以下bebavior不会改变:

@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;
        }

有人能解释那里发生了什么吗? 为什么第二种情况也有效? 如果PlatformTransactionManagerSimpleMessageListenerContainer上注册,那么内部会有什么不同。

假设transactionManager是你的数据库tm,因为你的监听器是@Transactional ,所以这些场景没有太大的区别。

在第一种情况下,事务在调用侦听器之前由容器启动(实际上在从内部队列检索消息之前,因此即使没有消息也会启动事务)。

在第二种情况下,当我们调用侦听器时,事务拦截器启动事务。

考虑一下监听器不是事务性的情况,但是某些下游组件是; 假设侦听器成功调用该组件,然后在抛出异常之前再做一些工作。 在这种情况下,数据库提交将成功并且消息被拒绝。 这可能不是理想的行为,特别是如果消息被重新排队。 在这种情况下,通常通过注入数据库tm来使兔子事务与数据库事务同步更好。

在你的情况下,数据库提交和兔子确认之间几乎没有机会失败,所以这真的不适用于你的情况,你不需要容器中的tm。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM