【问题标题】:Reliably tracking changes made by Hibernate可靠地跟踪 Hibernate 所做的更改
【发布时间】:2018-04-25 13:09:31
【问题描述】:

我正在使用PostUpdateEventListener 注册通过

registry.appendListeners(EventType.POST_COMMIT_UPDATE, listener)

和其他一些侦听器以跟踪 Hibernate 所做的更改。这完美地工作,但是,我在那里看到一个问题:

假设,为了通过id 跟踪一些amount,我只需执行

 amountByIdConcurrentMap.put(id, amount);

在每个POST_COMMIT_UPDATE 上(让我们忽略其他操作)。问题是这个调用发生在提交之后的某个时间。因此,由于两个提交一个接一个地写入同一个实体,我可以以错误的顺序接收事件,最终存储较旧的amount

  • 这真的可能吗?或者操作是否以某种方式同步?
  • 有没有办法防止或至少检测到这种情况?

【问题讨论】:

    标签: java hibernate concurrency transactions


    【解决方案1】:

    两个问题,稍后提出一个建议

    1. 您确定需要此优化。为什么不通过查询来获取写入数据库的金额。是什么让您有理由使用缓存。

    2. 您如何确保在将其写入数据库之前对金额的计算已正确同步,以便多个线程或可能的节点不使用旧数据来计算金额并因此覆盖结果以后的计算?

    我想您正确处理了第 2 个问题。然后你必须选择:

    1. 悲观锁定,这意味着您可以在提交之前以独占方式更新缓存而不会出现并发问题。
    2. 乐观锁定:在这种情况下,您的数据库记录中有一种时间戳或计数器,您也可以将其与数量一起放入缓存中。您可以使用此值找出最近的值是什么。

    【讨论】:

    • 我实际上正在使用乐观锁定,所以我可能只需要比较像map.compute(id, (k, v) -> v==null || timestamp.isAfter(v.timestamp) ? new Value(timestamp, amount) : v) 这样的时间戳。这听起来很简单。
    • maartinus 好的,但请确保仅进行此更改。在 isAfter 和设置值之间,另一个线程可以更改内容
    • maartinus,并且在集群环境中,请注意,如果缓存中的最新值不是分布式的,例如 infinispan,您可能看不到缓存中的最新值。
    • 谢谢!我想,这一切应该很顺利。 map,我的意思是concurrentMap(它在键上同步compute)。我得到的值来自PostUpdateEvent#newState,并且是Session 的私有值。我还没有使用集群,我知道它会变得很复杂。
    【解决方案2】:

    不,没有订购保证,因此您必须注意手动确保正确同步。

    如果您要解决的真正问题是实体状态的缓存,并且如果适合对相关实体使用二级缓存,那么您可以通过启用 L2 缓存来立即使用所有内容。

    否则,您可以将任务提交到 Executor 或消息系统,该系统将异步启动新事务和 select for update 数据库中给定 id 的数量,而不是直接从更新侦听器更新地图。然后在同一个事务中更新map,同时在db中持有对应的行锁,这样同一个id的map更新是串行完成的。

    【讨论】:

    • 当二级缓存可以做得更好时,它必须使用比拦截器/侦听器更好的机制,不是吗? +++另一个答案may lead to a simple solution,你怎么看?
    • @maaartinus 为确保一致性,L2 缓存使用软锁进行读写缓存并依赖 XA 协议进行事务缓存,它不使用实体更新侦听器。
    • 关于另一个答案,如果你看一下我的答案的编辑历史,我最初也建议选项1,但后来我意识到这意味着在提交事务之前将更改发布到地图,所以我删除了它。关于时间戳,两个并发更新的时间戳仍然可以相同,而且很难保证它们的顺序与两个并发事务实际提交的顺序相对应。
    • 但是,如果您不使用集群,则按照@aschoerk 的建议,将计数器与缓存中的数量一起存储,看起来是个好主意。
    • @maaartinus 我建议了一种更通用的方法,在数据库级别进行同步,应该涵盖大多数情况。当然,如果您通过在其他东西上同步来防止重新读取数据和更新地图之间可能出现的竞争条件,那也很好。
    猜你喜欢
    • 2012-03-18
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    相关资源
    最近更新 更多