代码之家  ›  专栏  ›  技术社区  ›  artemb

如何在jboss下保持EntityManager的缓存与Hibernate处于一致状态?

  •  1
  • artemb  · 技术社区  · 16 年前

    我们正在使用Hibernate运行JBoss,并出现此问题。

    当会话be an使用EntityManager查找实体时,它可能已经存在于EntityManager的缓存中,并且其状态可能已经过时。如果代码使用这样一个实体来做决定,它可能会做出错误的决定,从而产生错误。

    下面是一个例子。

    HTTP请求1。会话bean创建一个实体实例,并将其存储为字段“a”设置为值1。持久化实体的ID为4。

    HTTP请求2。会话bean查找id=4的实体,将其字段“a”设置为值2并保存它。

    HTTP请求3。会话bean查找id=4的实体并检查其字段“a”。如果值为1,则执行一件事;如果值为2,则执行另一件事。

    如果请求3中的em恰好与请求1中的em相同,则会发生不希望发生的行为。我已经测试过了,大约有10%的失败案例。

    所以问题是-如何避免这种情况?每次我必须确保实体是最新的,调用em.refresh()或em.clear()似乎是浪费资源。

    1 回复  |  直到 16 年前
        1
  •  1
  •   Community CDub    8 年前

    阿特姆

    这似乎是一个 recurring theme 在你的问题中:—)

    虽然我知道你以前得到的答案(包括我的)可能不是你希望得到的,但它们不会改变:

    • 实体管理器是一个映射到休眠会话的,通常需要是短期的。 Here 是有关休眠会话的工作单元、事务和范围的一个很好的解释,如果您以前没有看到过,请看一看。
    • 如果你的申请是 一贯地 紧紧抓住实体经理,你需要认真考虑改变这一策略;如果你只是在一些你真正需要长时间交易而不是使用 refresh() 方法肯定是所有邪恶中的较小者。
    • 不像 second level cache 具有集群实现的会话级缓存在不同的会话(实体管理器)之间不同步。 按设计 同一实体的并发更新通过 optimistic locking 由休眠或应用程序级锁定提供。
    • 理论上,您可以(只要您的ORM访问被充分分离)维护您自己的缓存(如果需要的话可以集群),这些缓存由不同的实体管理器持有;您需要适当地注册 event listeners 使缓存保持同步。不过,我强烈建议您不要采用这种方法——不仅它涉及到实现和易出现错误,而且您还将反对Hibernate的这种模式。