【问题标题】:Cache a whole database using Spring, Hibernate, and Ehcache使用 Spring、Hibernate 和 Ehcache 缓存整个数据库
【发布时间】:2015-10-11 17:55:44
【问题描述】:

我正在开发一个依赖于缓存的应用程序,主要使用读取和一些更新。

我使用的技术栈是 Spring + Hibernate + Ehcache。 我需要使用缓存来服务请求,而根本不访问数据库。 我遵循的方法是在应用程序启动时使用 getSession().createCriteria(<Entity>.class).list() 之类的查询缓存所有数据,然后使用 session.get() 调用向 Hibernate 询问实体,以便它使用二级缓存来解析。

我看到的一个挑战是我的实体类有很多集合和关联属性(带有额外列的多对多、一对多、一对一)。

对于这样的缓存,我有两种方法:

  1. 将所有关系保持为 EAGER fetch。缓存将在启动时使用包含左外连接的大查询填充数据。 我担心急切地加载数据可能会导致不必要的长时间运行的查询返回多行。

  2. 将关系保持为 LAZY 并遍历所有行并调用 .getSetOf<Entity> 以加载相关实体。 我担心我会在启动时对所有数据进行虚拟迭代,我不确定这是否是一种好的做法。

由于 Hibernate 中的关联是使用组合键和外键关联的,而不是存储为单独的 ID,因此加载此类关联/集合似乎是开销。

我希望将表数据放在不同的缓存区域中,它们的外键关系只是 ID(而不是组合/集合)。我会将所有此类实体缓存在不同的区域中,并在运行时通过迭代这些区域来组合结果。

谁能建议我应该采用什么方法?如果有任何替代方法,请提出建议。

【问题讨论】:

    标签: java spring hibernate caching


    【解决方案1】:

    我正在从事一个具有技术堆栈spring+hibernate+hazelcast的项目。我也在使用 hibernate 二级缓存。我们还在服务器启动时将数据加载到缓存中。 根据我的说法,您不应该对实体进行所有集合,因为它会使对象非常沉重。我们正在使用混合方法。我们的一些集合是急切的,有些是懒惰的,具体取决于要求。如果你的集合有非常大的数据,那么让它变得懒惰,否则让它变得急切。 我们正在做的另一件事是,我们在查询中使用LEFT JOIN FETCH,如果集合被定义为惰性,我们也会加载集合。例如:-

    SELECT DISTINCT userInfo FROM UserInfo userInfo
    LEFT JOIN FETCH userInfo.userRoles
    LEFT JOIN FETCH userInfo.regions
    LEFT JOIN FETCH userInfo.countries
    

    在我的实体 UserInfo 中,我创建了区域 Eager(因为区域数量较少)和国家 Lazy(因为国家数量较多)。现在我的这个查询仍然返回完全加载了国家和地区的 userInfo 对象。并且由于 Left Join Fetch 没有执行多个查询。

    希望对你有帮助。

    【讨论】:

    • 感谢您的回复。。请问您何时需要将角色添加到 userRole 集合中。(例如 userInfo.getuserRoles().add(new UserRole())) 添加的那一刻,休眠使集合无效。下次您使用 userInfo.getUserRoles() 时,它会再次查询 Db。任何可以处理的方式。即如何避免这种缓存失效?
    • 我们正在刷新缓存以防失效。是的,你是对的,我们将再次访问数据库以获取更新的用户信息。
    • 你认为使用 Core Ehcache API 是一种方法吗?我将在启动时使用 EHcache API 缓存数据,并具有添加/删除/修改缓存的灵活性,而不依赖于 Hibernate这样做。
    • 对不起,您的要求我不清楚。您能解释一下吗?
    【解决方案2】:

    从您的描述中不清楚您的应用程序是否控制对数据库的访问。

    • 如果不是,那么performance documentation 表示您可能会遇到过时数据的风险。在这种情况下你会怎么做?
    • 如果是且仅当您确实需要最小化 db 命中数时,我不会使用 Hibernate 或 Ehcache。除了初始加载之外,没有多少 ORM 发生,在我看来,这并不能使它成为 Hibernate 的一个用例。我会在启动时使用带有批处理选择的 Spring JDBC。这将减少调用次数和可能的内存不足异常(“正常”选择语句引用其读取数据,因此当您通过记录进行时,您将拥有更多无法被 GC 处理的引用)。它还减少了您的技术堆栈,减少了 1 个负担。您可以在更改状态后立即更新缓存和数据库。您可能需要考虑事务范围。左连接可以在您的映射器中处理。我也会放弃 OO 方法并使用数据数组或映射。仅仅为了它而用一个对象封装每组数据可能是矫枉过正(内存消耗,cpu,...)。特别是一次性加载的要求让我觉得这里没有发生太多的交互。并删除 Ehcache。如果您确实需要最大限度地减少数据库调用,您也可以将所有内容都放在 Map 中,因为不需要驱逐策略。

    明确一点,我不反对 OO 或 Hibernate 或 Ehcache。我只是想知道它们是否适合您的(有限)描述。

    【讨论】:

      猜你喜欢
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      • 2014-06-04
      • 2013-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多