我想在这里了解一些事情。我的要求是我想在db中存储记录并希望将消息发送到队列然后让我们说同样的方法如果它抛出一些异常我不想发送消息而不想提交db事务。 现在我想到使用spring事务但是由于两个不同的资源,想到使用JTA使用一些atomikos来同步资源 - 但我再次读取RMQ不支持2PC或XA等。 无论如何,我继续前进并首先尝试没有添加atomikos,我所做的只是确保我的频道交易和@Transaction注释小心,请参阅下面的示例代码 - 我没有在pom中添加任何特殊内容。
现在我的问题是这是如何工作的,这与2PC有什么不同 - 以及什么情况可能会使用这种方法弄乱最终的一致性。令人惊讶的是,为什么我不必使用第三方jta。如果一切都很好 - 当我们使用春天的好东西使用rmq和db时,这似乎是最终的一致性保证!对于微服务:)
如果这不是一个好的解决方案,那么什么是替代方案 - 我希望尽可能避免工人流程等最终的一致性。
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setChannelTransacted(true);
return rabbitTemplate;
}
@GetMapping
@Transactional
public void sampleEndpoint(@RequestParam boolean throwException){
Customer a=new Customer();
a.setCustomerName("XYZ");
customerRepository.save(a);
rabbitTemplate.convertAndSend("txtest","Test");
if(throwException)
throw new RuntimeException();
}
我使用spring boot 1.5.7
在上面的例子中使用了postgres依赖答案 0 :(得分:3)
我建议你阅读Dave Syer's article: Distributed transactions in Spring, with and without XA。
您需要在数据库事务之前启动Rabbit事务,以便Rabbit事务与DB事务同步,并在DB tx之后很快提交,并在DB tx回滚时回滚。
DB tx提交成功的可能性很小,但Rabbit tx回滚。这篇文章被称为“Best Effort 1PC”。您需要处理重复消息的可能性很小。
您没有显示所有配置,但看起来您的Rabbit tx将在数据库之前提交,这可能不是您想要的。
答案 1 :(得分:2)
关于“它是如何工作的”问题,spring-amqp文档中的引文阐明了:
如果在框架发送或接收消息时已经有一个事务在进行中,并且channelTransacted标志为true,则将消息事务的提交或回滚推迟到当前事务结束为止。如果channelTransacted标志为false,则没有事务语义适用于消息传递操作(它是自动确认的)。
我的理解是,对于您的用例,您甚至不需要配置ChainedTransactionManager即可实现Best Effort 1PC。 @Transactional就足够了,兔子tx将在DB tx之后提交。