spring-boot - @JmsListener 并持久化到数据库

标签 spring-boot jpa jms jta spring-boot-jpa

我正在开发一项服务,在该服务中我监听队列、反序列化接收到的消息并将它们保存到数据库 (Oracle)。大致:

@JmsListener(destination="some-destination")
public void onMessage(Message message) throws Exception {
    String message = ((TextMessage) message).getText();
    service.save(deserialize(message));
    // includes exception handling etc
}
在默认的消息监听器 bean 中,我设置了并发性和 setSessionTransacted(true) .这足以使整个 onMessage 具有事务性吗?以便在一个事务中接收并保存一条消息,并在其中任何一点出现故障时回滚?
当尝试保存特定消息时,我尝试在特定消息上抛出异常 - 消息确实回滚到队列中,并且监听器尝试再次使用它们,这是一种期望的行为。
在研究这个的时候,我偶然发现了分布式事务,jta事务管理器,但我仍然不确定除了setSessionTransacted(true)之外是否还需要配置更多,或者Spring Boot是否自动处理XA资源的事务。
寻求建议。谢谢你。

最佳答案

如果您的听众的 onMessage()除了调用 setSessionTransacted(true) 之外,它正在与接收消息的 JMS 代理以外的事务资源进行交互。是 不是 足以使所有交互成为事务性的。
JMS 中的“事务处理” session 仅涵盖具有该特定 session 的 JMS 操作。它不包括使用任何其他事务资源(例如数据库)的工作。
如果您想要一个涉及监听器消费消息的事务以及监听器完成的任何其他事务性工作(例如,在数据库中更新或插入记录、将 JMS 消息发送到另一个代理等),那么您需要一个 JTA事务管理器可以与 XA 资源一起工作以协调各种事务阶段(例如准备、提交、回滚)。这些类型的事务有时称为“分布式”事务。
这是一个相当常见的用例,因为它使 JMS 消息成为一种“工作单元”,并且您知道如果消息被使用,则与该消息相关的所有工作也已成功完成,反之亦然。这是 MDB 在 Java EE 中提供的主要功能之一,但同样的基本工作也可以在 Spring 中完成。
根据Spring Boot documentation您可以与少数不同的事务管理器(例如 Atomikos、Bitronix、Narayana 等)集成来完成此类工作。
需要明确的是,在某些情况下,您现有的安排会使两个操作看起来像是在同一个事务中。例如,如果您的数据库操作抛出异常,而该异常是从 onMessage() 抛出的。然后消息将回滚到队列中。然而,在这种情况下,这两个操作只是相关的。它们不在同一个事务中,因此它们实际上不是原子的。如果数据库操作成功了,然后由于某种原因从监听器的 onMessage() 抛出另一个异常。或者 JMS 代理在事务 session 可以提交之前崩溃,那么消息最终将回滚到队列中,但数据仍将在数据库中,因此如果您再次使用该消息,您表面上会写入相同的数据再次数据库。

关于spring-boot - @JmsListener 并持久化到数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64174065/

相关文章:

java - 返回响应自定义 JSON,该响应返回经过验证的响应以在 BD Spring Boot 中执行存储过程

sql - 使用liquibase修改SQL-Server中的数据类型和数据

java - 使用占位符时无法导入属性值

jms - 有没有办法更改 Nifi 中 PublishJMS 处理器的交付模式?

jms - 没有看到我明确设置的消息属性 (Spring/JMS/MQ)

java - 使用 JMSMessageID 从 MQ 队列中删除 JMS 消息

java - Spring-Boot-Test @MockBeans 是否应该符合 @ConditionalOnBean 条件?

spring - JPA、Hibernate 和 Spring 集成 : Table doesn't exist Error

java - Jackson JSON 和延迟加载集合

sql-server - 是否可以在没有 XA 的事务中拥有两个 MSSQL 持久性单元?