为什么亚马逊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' 不是真正的事务性的,即使在你的兔子例子中也是如此。
考虑交易运作的基础知识:
- 某种
begin
步骤,表示以下更改是事务的一部分
- 进行了更改(但读者不可见)
- 某种
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。允许暂时的不一致并具有使系统最终一致的机制通常更容易和更快。
在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' 不是真正的事务性的,即使在你的兔子例子中也是如此。
考虑交易运作的基础知识:
- 某种
begin
步骤,表示以下更改是事务的一部分 - 进行了更改(但读者不可见)
- 某种
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。允许暂时的不一致并具有使系统最终一致的机制通常更容易和更快。