【问题标题】:@JmsListener and persisting to database@JmsListener 并持久化到数据库
【发布时间】:2020-10-02 15:15:17
【问题描述】:

我正在开发一项服务,在该服务中我侦听队列、反序列化收到的消息并将它们保存到数据库 (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资源的事务。 寻求建议。谢谢。

【问题讨论】:

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


    【解决方案1】:

    如果您的侦听器的 onMessage() 正在与事务资源交互,而不是从其接收消息的 JMS 代理,那么调用 setSessionTransacted(true) 不足以交互事务。

    JMS 中的“事务”会话仅涵盖具有该特定会话的 JMS 操作。它不包括使用任何其他事务性资源(例如数据库)。

    如果您想要一个涉及侦听器对消息的消费以及侦听器完成的任何其他事务性工作(例如,在数据库中更新或插入记录、将 JMS 消息发送到另一个代理等)的事务,那么您需要一个可以使用 XA 资源的 JTA 事务管理器,以协调各种事务阶段(例如准备、提交、回滚)。这类交易有时称为“分布式”交易。

    这是一个相当常见的用例,因为它使 JMS 消息成为一种“工作单元”,并且您知道如果消息已被消费,那么与该消息相关的所有工作也都已成功完成,反之亦然.这是 MDB 在 Java EE 中提供的主要功能之一,但同样的基本工作也可以在 Spring 中完成。

    根据Spring Boot documentation,您可以与少数不同的事务管理器(例如 Atomikos、Bitronix、Narayana 等)集成来完成此类工作。

    需要明确的是,在某些情况下,您现有的安排会以这样的方式起作用,以使这两个操作看起来像是在同一个事务中。例如,如果您的数据库操作引发异常并且该异常是从onMessage() 引发的,则消息将回滚到队列中。然而,在这种情况下,这两个操作只是相关。它们不在同一个事务中,因此它们实际上不是原子的。相反,如果数据库操作成功,然后由于某种原因从侦听器的onMessage() 引发另一个异常,或者 JMS 代理在事务会话可以提交之前崩溃,则消息最终将回滚到队列中,但数据也会仍然在数据库中,因此如果您再次使用该消息,您表面上会再次将相同的数据写入数据库。

    【讨论】:

    • 在这种情况下,是否必须使用 Atomikos 之类的东西来构建事务管理器?
    • 谢谢。我仍然不确定为什么它似乎在不配置事务管理器的情况下工作 - 如果在执行数据库相关操作时抛出任何问题/异常,消息将回滚到队列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 2015-08-19
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多