【问题标题】:Merge data from 2 messages in 1 entity在 1 个实体中合并来自 2 条消息的数据
【发布时间】:2019-04-11 07:28:31
【问题描述】:

我有一个 JMS 队列,在多个集群节点上有多个消费者。我收到来自不同发件人的消息。可能有多条消息,其中只有一个实体的信息。实体需要使用 jpa 进行持久化。当接收到实体的消息时,该实体可能已经存在也可能不存在于数据库中。

当 2 个消费者同时处理同一实体的消息时,就会出现问题。两个消费者都尝试在数据库中查找实体。因为没有找到实体,所以两者都尝试插入实体而不是更新现有实体。因此,速度越快的一方获胜,另一方最终出现异常(因为表上的唯一键约束)。

我想到了一个令人讨厌的解决方案,方法是尝试/赶上一个刷新调用。但是我使用的是容器管理的事务,刷新和事务结束之间还是有差距的。

第二个想法是关于合并和持久化之间的区别。但即使它可以与合并一起使用,它也会导致覆盖现有数据。

我认为这一定是一个非常普遍的挑战,但直到现在我还没有找到一个干净的解决方案。可能我想错了方向。

感谢任何帮助。

【问题讨论】:

  • 嗨,Ben,如果您将“测试”括起来并插入到同一个数据库事务中,则第二个使用者永远不应进入测试成功但插入失败的状态。您是否使用显式事务开始和提交?
  • 'test' 和 insert 发生在同一个事务中。但是,如果消费者 1 中的事务尚未提交,则其更改对消费者 2 不可见。因此,如果事务 1 在消费者 2 中的“测试”之后提交,则会出现问题。至少我认为我是这样发生的。
  • 您好 Ben,如果您的 DB 事务按预期工作,那么在消费者 1 进行测试和插入时,消费者 2 将被阻塞。您如何开始和停止交易?
  • 嗨阿克塞尔。事务由容器 (EJB) 启动和停止。我认为这是数据库隔离级别的问题。就我而言,应该是“已阅读”。因此,允许“幻读”(link)。我想这就是这里发生的事情?在“插入”的情况下,整个表没有锁定。还是我错了?
  • 嗨,Ben,是的,同意了。使用这种隔离级别,您可能会遇到麻烦。我认为您正在做的是并行化(当前)不可并行化的算法。是否可以在启动时预先创建所有实体?在实体 A 上更新 1 价格为 100 ,然后在同一实体上更新 2 价格为 102 到底意味着什么?由于您正在与这些消费者“并行化”它,因此更新 2 可能会超过更新 1。

标签: jpa concurrency jms weblogic


【解决方案1】:

如果您的 JMS 提供程序支持消息组,您可以将特定实体的所有消息放入一个组中,这样同一组中的所有消息将发送给同一个使用者并按顺序而不是同时处理,从而避免比赛条件。

通常会实现消息组支持,以便消息是否来自同一个生产者无关紧要,因为有一种方法可以从消息内容中确定地识别组 ID。例如,如果您要发送带有要存储在数据库中的数据的消息,则可以将组 ID 设置为主键。因此,具有相同主键的消息将在同一个组中,并被同一个消费者消费。

分组消息在队列中可用时立即被使用,就像普通消息一样。普通消息和分组消息之间的唯一区别是它们总是发送给同一个消费者。组是否“完整”无关紧要。

【讨论】:

  • 我认为这行不通,因为我有不同的制作人,而且他们彼此不认识。所以我认为这在生产者方面是无法实现的。如果这是在队列/消费者端完成的,如何知道一个组是否“完整”?什么时候开始处理?
  • 哦,现在我明白了。我正在使用 Weblogic。首先,我查看了工作单元功能,但我认为需要有一个增量序列和一个“结束”消息。但是还有一个 Unit-of-Order-functionality,它不需要序列,但与消息的创建日期一起使用。那应该可以满足我的需要。下周会试一试。感谢您指向正确方向的指针!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多