为了简化我的问题,我有
App1与@Transactionnal方法createUser():
App2与RabbitMQ消息消费者
问题在于,有时App2会在App1上提交事务之前尝试使用RabbitMQ消息。这意味着App2无法读取数据库上的邮件数据,因为尚未创建用户。
有些解决方案可能是:
我已经看到Spring中有一个RabbitTransactionManager,但我无法理解它应该如何工作。事务处理内容似乎总是有点难以理解,文档也没有那么多帮助。
有没有办法做这样的事情?
如何?如果我发送同步RabbitMQ消息而不是异步消息,那么可以期待什么呢?它会阻止等待响应的线程吗? 因为我们确实为不同的用例发送同步和异步消息。
答案 0 :(得分:2)
我知道这已经晚了,但由于我当时对@Transactional的理解有限,我也遇到了同样的问题。所以对于碰巧遇到这种情况的其他人来说,这更为重要。
当使用@Transactional将数据保存到数据库时,保存到数据库实际上不会发生,直到方法返回,而不是在调用save时。
所以,如果你有像
这样的方法@Transactional(readOnly=false)
public void save(Object object) { //Object should be one of your entities
entityManager.persist(object); //or however you have it set up
rabbitTemplate.convertAndSend(message); //again - however yours is
}
即使您在将消息放入队列之前调用对象上的持久性,在方法返回之前实际上不会发生持久化,从而导致在方法返回之前和数据之前将消息放入队列实际上是在数据库中。
可以嵌套@Transactional方法(不直接)可以在save()
方法返回后将消息放入队列。但是,您无法将消息放入队列并期望它不被消耗。一旦它消失了。因此,如果需要,请延迟将其放入队列。
如果要以同步方式从队列接收响应。在我的函数示例中 - 您可以执行此操作,但是它只会使实际持久化数据需要更长时间,因为它将在方法返回并实际持久保存数据之前等待来自worker的响应。 (还要记住,从排队的消息中接收响应有一个超时)。
所以我建议不要将这两个操作放在同一个@Transactional
中答案 1 :(得分:1)
我对@Transactionnal和spring并不熟悉,但在AMQP中,标准消息队列不是事务操作,因此您必须将数据存储在db中(如果db connection是事务性 - 提交事务)并且仅在发送消息之后经纪人。
正确的工作流程就像App1: createUser -> notifyUser; App2: listenForNotifications