为了简化我的问题,我有
带有@Transactionnal 方法 createUser() 的 App1:
带有 RabbitMQ 消息消费者的 App2
问题是有时,App2 甚至在 App1 上提交事务之前尝试使用 RabbitMQ 消息。这意味着 App2 无法读取数据库中的邮件数据,因为用户尚未创建。
一些解决方案可能是:
我已经看到 Spring 中有一个 RabbitTransactionManager,但我不明白它应该如何工作。事务处理内部的东西似乎总是有点难以理解,文档也没有多大帮助。
有没有办法做这样的事情?
如何?例如,如果我发送同步 RabbitMQ 消息而不是异步消息,会发生什么?它会阻止线程等待响应还是什么?
因为我们确实为不同的用例发送同步和异步消息。
最佳答案
我知道这已经晚了,但由于当时我对 @Transactional 的理解有限,我遇到了同样的问题。所以这对你偶然发现的其他人来说更是如此。
当使用@Transactional 将数据保存到数据库时,在方法返回之前不会实际发生到数据库的保存,而不是在调用保存时。
所以如果你有一个像
@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()
之后的队列中方法返回。但是,您不能将消息放入队列并期望它不会被使用。一旦它消失了。因此,如果需要,请延迟将其放入队列。如果您想以同步方式从队列接收响应。在我的函数示例中 - 您可以这样做,但是它只会使实际持久化数据花费更长的时间,因为它将在方法返回并实际持久化数据之前等待工作人员的响应。 (还请记住,从排队消息接收响应有一个超时)。
所以我的建议是不要将这 2 个操作放在同一个 @Transactional 中
关于 Spring /RabbitMQ : transaction management,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17431367/