【问题标题】:Transactions with multiple resources (database and JMS broker)具有多个资源的事务(数据库和 JMS 代理)
【发布时间】:2020-01-27 10:39:13
【问题描述】:

我有一个应用程序,我们在其中插入数据库并将事件发布到 ActiveMQ。

我遇到了交易问题。我将用下面的代码解释这个问题:

@Transactional(rollbackFor = Exception.class)
public class ProcessInvoice {

    public boolean insertInvoice(Object obj){

        /* Some processing logic here */

        /* DB Insert */
        insert(obj);

        /* Some processing logic here again */

        /* Send event to Queue 1 */
        sendEvent(obj);

        /* Send event to Queue 2 */
        sendEvent(obj);

        return true;
    }
}

类用@Transactional 注释,在insertInvoice 方法中我正在做一些处理,插入数据库,并将事件发送到两个队列。

使用上面的代码我面临两个问题:

  1. 如果队列很慢,那么我将面临性能问题,因为sendEvent 方法中的进程需要时间。

  2. 如果由于某种原因 ActiveMQ 宕机或消费者无法处理消息,如何回滚事务?

如何处理这些问题?

【问题讨论】:

    标签: java spring transactions activemq


    【解决方案1】:

    我对您的问题有一些疑问:

    • 如果 sendEvent(Object o) 方法在性能方面如此昂贵(根据您所说的),您为什么要考虑调用它两次(显然是为了处理同一个对象)?

    显然,这 2 个调用的结果是相同的,不同之处在于它们将被发送到 2 个不同的队列。我相信您可以在一次调用中将其发送到两个队列,以免重复执行相同的代码。

    • 在考虑事务时,我首先想到的是同步操作。您想异步还是同步执行这些操作?例如,您是否要等到发票插入 DB 后再将消息发送到 Queue1 和 Queue2?

    也许您应该异步执行此操作。如果您不这样做或不能,也许您可​​以选择“乐观”策略,首先将消息发送到 Queue1 和 Queue2,然后在代理端处理这些消息时,执行发票的插入进入数据库。如果数据库具有高可用性,在大多数情况下插入会成功,因此您不必等到它被持久化后才能将消息发送到 Queue1 和 2。万一插入不成功(不太可能) ,您可以发送第二条消息以撤消代理端的这些更改。如果由于您的业务逻辑,此“撤消”过程并非易事,则此替代方案可能不适合您。

    您提到如果 ActiveMQ 已关闭,如何回滚。好吧,在这种情况下,您可能需要对队列进行一些监控,以了解消息是否到达目的地。我建议你看看Advisory messages,他们可能会帮助你控制它并采取相应的行动。

    但也许您也可以使用durable subscribers 重新考虑和解决您的需求,这样一旦订阅者再次可用,他们就会收到排队的消息。但这表现稍差,因为它需要将消息持久化到文件中,以便在代理出现故障时恢复它们。

    希望这些建议对您有所帮助,但我认为您应该更多地描述您想要的结果(流程),因为它似乎不是很清楚(至少对我而言)

    【讨论】:

    • JMS 本身不支持通过一次javax.jms.Producer#send() 调用将消息发送到多个目的地。但是,ActiveMQ 支持称为 composite destinations 的东西,它支持这种行为。性能最终是否会更好将取决于行为的实际实现方式。在我看来,优化操作是短视的,除非您确定它们实际上是瓶颈,并且到目前为止还没有提供任何证据来表明瓶颈的实际位置。
    • 我的回答是否解决了您的问题?如果是这样,请将其标记为正确,以帮助将来有相同问题的其他用户。如果不是,请详细说明原因。谢谢!
    【解决方案2】:

    如果您需要以事务方式发送消息(即您需要确保代理在您发送消息时确实收到了您的消息)并且代理执行缓慢而影响您的应用程序,那么您只有两个选择:

    1. 接受应用程序中的性能损失。
    2. 提高代理的性能,以便您的应用程序性能也得到提高。提高经纪人绩效是另一回事。

    在 JMS(和大多数其他消息传递体系结构)中,生产者和消费者在设计上并不知道彼此。因此,您将不知道您发送的消息的使用者是否因任何原因无法处理该消息,至少不是通过任何自动 JMS 机制。

    当代理关闭时,sendEvent 方法应该彻底失败。但是,我对 Spring 如何处理事务并不是非常熟悉,所以我不能说在这方面应该发生什么。

    【讨论】:

      猜你喜欢
      • 2019-07-02
      • 2022-09-27
      • 2014-05-27
      • 1970-01-01
      • 1970-01-01
      • 2016-09-25
      • 2022-01-23
      • 2023-03-08
      • 2018-07-11
      相关资源
      最近更新 更多