【发布时间】: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