【问题标题】:Hibernate loading all entities utilizing 1st or 2nd level cache休眠加载所有使用一级或二级缓存的实体
【发布时间】:2011-04-06 12:50:37
【问题描述】:

我们需要在休眠会话期间加载整个实体表,而我知道加载所有实体的唯一方法是通过 HQL 查询:

public <T> List<T> getAllEntities(final Class<T> entityClass) {
    if (null == entityClass)
        throw new IllegalArgumentException("entityClass can't be null");

    List<T> list = castResultList(createQuery(
            "select e from " + entityClass.getSimpleName() + " e ").list());


    return list;
}

我们使用 EHcache 进行二级缓存。

问题是这在给定的事务会话中被调用了 100 次,并且占用了总时间的相当一部分。有没有办法加载给定类型的所有实体(加载整个表)并且仍然受益于一级会话缓存或二级 ehcache。

我们被告知要远离查询缓存,因为相对于它们的收益而言,它们可能会降低性能。 * Hibernate Query Cache considered harmful

虽然我们现在正在进行性能分析,所以可能是时候尝试打开查询缓存了。

【问题讨论】:

  • 为什么您的代码首先在同一个事务中重新加载整个表 100 次?如果是因为其他线程可能正在执行插入操作,那么即使您以某种晦涩难懂的方式重写代码来使用它们,L1 和 L2 缓存都无法为您提供太多帮助。
  • 这是一个静态表(至少每 24 小时是静态的)更重要的是,该方法在给定的事务中被调用了 100 次,我们可以轻松地在 DAO 中为该事务“缓存”该方法,但我很好奇如果我以不同的方式加载表,我是否正在重新发明已经完成的缓存。

标签: java hibernate orm caching ehcache


【解决方案1】:

L1 和 L2 缓存对于“获取整张表”的问题没有多大帮助。

L1 缓存设备不完善,因为如果其他人插入了什么东西,它就不存在了。 (您可能“知道”在系统的业务规则范围内没有其他人会这样做,但 Hibernate Session 不会。)因此,您必须查看数据库以确定。

使用 L2 缓存,自上次有人将表放入其中以来,事物可能已经过期或刷新。这可以由缓存提供者支配,甚至完全在外部完成,可能通过 MBean。因此,Hibernate 在任何给定时间都无法真正知道该类型的缓存中的内容是否代表了表的全部内容。同样,您必须查看数据库才能确定。

由于您对该实体有特殊的了解(永远不会创建新的实体),因此没有实用的方法来传授 L1 或 L2 缓存,因此您需要使用 Hibernate 提供的工具,以备不时之需关于结果集、查询缓存或自己缓存信息的业务规则级知识。

--

如果您真的希望它在 L2 缓存中,理论上您可以将集合的表成员中的所有实体都放在某个其他虚假实体上,然后启用缓存集合并在 DAO 中秘密管理它。不过,我认为在你的代码中出现这种奇怪的东西可能不值得:)

【讨论】:

    【解决方案2】:

    当且仅当基础表经常更改时,才认为查询缓存是有害的。在您的情况下,表格每天更换一次。因此查询将在缓存中保留 24 小时。相信我:使用查询缓存。这是查询缓存的完美用例。

    有害查询缓存示例:如果您有一个用户表并且您使用查询缓存“from User where username = ...”,那么每次修改用户表时,此查询都会从缓存中逐出(另一个用户更改/删除他的帐户)。因此,对该表的任何修改都会触发缓存驱逐。改善这种情况的唯一方法是通过 natural-id 进行查询,但这是另一回事。

    如果您知道您的表每天只会修改一次,就像您的情况一样,查询缓存每天只会驱逐一次!

    但是修改表格时要注意你的逻辑。如果你通过休眠来做到这一点,一切都很好。如果您使用直接查询,您必须告诉 hibernate 您已经修改了表(类似于 query.addSynchronizedEntity(..))。如果您通过 shell 脚本执行此操作,则需要调整底层缓存区域的生存时间。

    您的答案是顺便重新实现查询缓存,因为查询缓存只缓存 id 列表。实际对象在 L1/L2 缓存中查找。所以在使用查询缓存的时候还是需要缓存实体。

    请将此标记为正确答案以供进一步参考。

    【讨论】:

      【解决方案3】:

      我们最终通过在内存中存储我们需要加载的表中所有实体的主键来解决这个问题(因为它们是模板数据,没有添加/删除新模板)。

      然后我们可以使用这个主键列表来查找每个实体并利用 Hibernates 一级和二级缓存。

      【讨论】:

        猜你喜欢
        • 2014-01-12
        • 2018-05-22
        • 2010-11-26
        • 2010-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多