为什么亚马逊sqs不支持交易?

Why does Amazon sqs not support transactions?

在Spring中,Rabbitmq支持事务。但是Amazon sqs不支持Spring.

的交易

对不起。我添加了更多内容。 我测试了两个消息队列(rabbitmq,amazon sqs),如下所示 spring.

我的目的是当用户无一例外地完成注册时,处理用户邮件到队列发送注册完成邮件的逻辑。

//rabbit mq configuration.class
@Bean
public ConnectionFactory rabbitConnectionFactory() {
    CachingConnectionFactory connectionFactory =
            new CachingConnectionFactory("localhost",5672);
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    return connectionFactory;
}

@Bean
public SimpleMessageListenerContainer messageListenerContainer() {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(rabbitConnectionFactory());
    container.setQueueNames(queue);
   container.setMessageListener(exampleListener());
    container.setTransactionManager(platformTransactionManager);
    container.setChannelTransacted(true);
    return container;
}


@Bean
public RabbitTemplate producerRabbitTemplate() {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory());
    rabbitTemplate.setQueue(queue);
    rabbitTemplate.setMandatory(true);
    rabbitTemplate.isChannelTransacted();
    rabbitTemplate.setChannelTransacted(true);
    return rabbitTemplate;
}



//UserService.class
@Autowired
private final UserRepository userRepository;
@Autowired
private final RabbitTemplate rabbitTemplate;

@Transactional
public User createUser(final User user){
    rabbitTemplate.convertAndSend("spring-boot", user.getEmail()); // SignUp Completion email
    final User user = userRepository.save(user);
    if(true) throw new RuntimeException();
    return user;
}

但是,上面的逻辑出现了runtimeException。

如果发生异常,由于 Spring 中的事务注释,Rabbit mq 将不会向队列发送数据。

//amazon sqs configuration.class
@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSqs) {

//UserService.class
@Autowired
private final UserRepository userRepository;
@Autowired
private QueueMessagingTemplate messagingTemplate;


@Transactional
public User createUser(final User user){
    messagingTemplate.convertAndSend("spring-boot", user.getEmail()); // SignUp Completion email
    final User user = userRepository.save(user);
    if(true) throw new RuntimeException();
    return user;
}

但是sqs即使出现异常也会向队列发送数据

有人知道这是为什么吗?

TLDR 我该如何解决这个问题?

不要尝试为此使用事务,想出一些方法使系统最终一致。


听起来您想执行 'queue.sendMessage' 和 'repository.save' 就好像它们是一个事务一样 - 两者都被提交,或者 none 被提交。问题是 'transaction' 不是真正的事务性的,即使在你的兔子例子中也是如此。

考虑交易运作的基础知识:

  1. 某种 begin 步骤,表示以下更改是事务的一部分
  2. 进行了更改(但读者不可见)
  3. 某种 commit 原子提交更改的步骤(使它们对读者可见)

但是,在您的情况下,队列和存储库是独立的实体,由独立的网络资源支持,彼此不通信。在这种情况下没有原子提交。没有原子提交,就不可能有真正的事务。它 "works" 在您的演示中,因为异常与执行写入的代码是分开的。

考虑这个案例以更清楚地说明:

@Transactional
public User createUser(final User user){
    messagingTemplate.convertAndSend("spring-boot", user.getEmail());
    final User user = userRepository.save(user);
    return user;
}
  • 当为此开始提交步骤时,它需要使消息(在队列中)和用户(在回购中)都可见
  • 为此,需要对队列和存储库进行网络调用
    • 这是两个调用的事实是问题的根源
  • 如果一个成功而另一个失败,你最终会处于不一致的状态
    • 您可能会说 "transactions can be rolled back" - 但回滚将涉及另一个网络调用,这当然可能会失败。

有很多方法可以使整个分布式系统事务化,但它是 very complex problem。允许暂时的不一致并具有使系统最终一致的机制通常更容易和更快。