如何在运行两个Java应用程序时维护Hibernate缓存一致性?

10
我们的设计中有一个JVM,是一个JBoss / Web应用程序(读/写),用于通过Hibernate(使用JPA)将数据维护到数据库中。该模型具有10-15个持久化类,并且在关系中有3-5层深度。
然后我们有一个单独的JVM作为服务器使用这些数据。由于其持续运行,因此我们只有一个长时间的数据库会话(只读)。
目前没有涉及任何内部JVM缓存-因此我们需要手动从另一个JVM中发出信号。
当Web应用程序更改某些数据时,它会向服务器发送信号以重新加载已更改的数据。我们发现需要告诉Hibernate清除数据,然后重新加载数据。仅使用数据库进行提取/合并无法完成此任务-主要是针对层次结构下面的多个对象。
请问是否有任何基本设计上的问题或者是否有人正在这样做并且在使用Hibernate重新加载方面有更好的运气?
谢谢, Chris
4个回答

14
一个Hibernate会话将其从数据库读取的所有数据加载到所谓的一级缓存中。当一行从数据库中加载后,任何对具有相同主键的行的后续获取都将从此缓存返回数据。此外,Hibernate保证同一会话中具有相同PK的对象具有引用相等性。
据我所知,只读服务器应用程序从不关闭其Hibernate会话。因此,当读写应用程序更新数据库时,只读服务器上的Session不知道更改。实际上,只读应用程序正在加载数据库的内存副本并使用该副本,而该副本在适当的情况下会变得过时。
我建议的最简单和最佳措施是根据需要关闭和打开会话。这样就可以规避整个问题。Hibernate会话旨在成为与DB短暂交互的窗口。我同意不再多次重新加载对象图形确实可以提高性能;但是您需要进行测量并让自己相信它值得付出努力。
另一个选择是定期关闭和重新打开会话。这确保只读应用程序使用不早于给定时间间隔的数据。但是,肯定存在只读应用程序使用过时数据的时间窗口(尽管设计保证它最终获得最新数据)。在许多应用程序中,这可能是允许的-您需要评估自己的情况。
第三个选项是使用二级缓存实现,并使用短暂会话。有各种具有相对优点和缺点的Hibernate缓存包。

使用JPA和@PersistenceContext获取EntityManager-但似乎我们需要@PersistenceUnit来获取EntityManagerFactory并刷新数据,我们会得到一个新的EntityManager。听起来不错 - 但这是一种笨重的更新方式,但如果人们这样做的话... - Chris Kimpton

5

Chris,我对你的情况有些困惑。如果我理解正确,你有一个Web应用程序(可读/写)和一个独立的应用程序(只读?),使用Hibernate访问共享数据库。你在Web应用程序中进行的更改不会在独立应用程序中显示。是这样吗?

如果是这样,您是否考虑使用不同的二级缓存实现?我想知道您是否能够使用由Web应用程序和独立应用程序共享的集群缓存。我相信与Hibernate集成的SwarmCache将允许此操作,但我自己还没有尝试过。

总的来说,您应该知道给定缓存的内容永远不会意识到另一个应用程序的活动(这就是为什么我建议两个应用程序共享缓存)。祝好运!


2
从我的角度来看,你应该将你的下划线 Hibernate 缓存更改为支持集群模式的缓存。它可以是 JBoss CacheSwarm Cache。第一个缓存具有更好的数据同步支持(复制和失效),还支持 JTA。
然后,您将能够配置 Web 应用程序和服务器之间的缓存同步。如果您使用 JBoss Cache,请注意隔离级别。我认为,如果您想从同一会话中的服务器获取新数据,则应使用 READ_COMMITTED 模式。

1
最常用的做法是使用容器管理的实体管理器,这样同一容器中(如Glassfish、Tomcat、Websphere)的两个或多个应用程序可以共享相同的缓存。 但如果您不使用应用程序容器,例如使用Play!,那么我会在主要应用程序中构建一些Web服务,以便在缓存中进行一致的读写。
我认为使用过时的数据是灾难的开端。就像单例变成多例一样,只读应用程序通常是有时写入安全第一 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接