【问题标题】:Second level cache vs query cache vs collection cache?二级缓存vs查询缓存vs集合缓存?
【发布时间】:2014-06-20 16:08:06
【问题描述】:

据我了解,使用主键加载对象时将使用二级缓存。这包括关联的获取。我只能想到上面的 session.get(),session.load 方法,二级缓存将进入图片。

如果关联是集合或其他实体,它如何被缓存?例如:-

  @Cacheable
  public class Department{
   private List Employees;
   private DepatmentDetail detail ;

}

如何使关联员工和详细信息可缓存?我想我需要在关联员工和详细信息上方提及@cache。 但这不起作用?

当开发人员执行 department.getEmployees() 时,hibernate 将在内部触发查询,即

 select * from employees where deptId =1;

现在,如果我使用查询缓存,我明确地进行上述查询并获取结果,查询将再次被触发到 db。为什么查询再次被触发。我认为这与hibernate如何在内部存储二级缓存和查询缓存的结果有关(它们可能存储在不同的区域中)。如果有人也能对这方面有所了解,那就太好了。

【问题讨论】:

  • 你在这里似乎很困惑。这些项目都是二级缓存的一部分。如果打开二级缓存,一切(几乎)都会通过它。所有会话都使用 same 二级缓存 - 这就是为什么它是二级缓存。每个会话也有它自己的缓存(如果你愿意的话,第一级缓存)。
  • 但是 b/w 二级和查询缓存的差异是什么?
  • 在您的示例中,您必须将 @Cache 注释放在员工实体本身上,因为集合缓存只包含员工主键 (id) 而不是实际的员工实例。这意味着如果员工本身也没有缓存,Hibernate 将不得不去 DB 加载它们。

标签: java hibernate second-level-cache


【解决方案1】:

我们需要明确地将@Cache(usage=CacheConcurrencyStrategy.<VALUE>) 放在集合上,将@Cacheable 放在相应的集合类上。 关于hibernate二级缓存here有很好的解释。

【讨论】:

    【解决方案2】:

    二级缓存内部有类似哈希表的结构来保存数据。这里的键是实体的标识符,值是实体的脱水值。要从这个 L2 缓存中取出数据,您必须有一个 Key,即实体的标识符。 很明显,您可以将它与通过 id 获取实体的方法一起使用。

    当您同时启用了 L2 缓存的 query_cache 时,这种情况会发生变化。查询缓存存储查询及其对应的结果集实体的 ID。 现在,即使您不是通过 id 获取(使用 JPQL 或 HQL OR queryDsl),hibernate 也会检查是否更早地触发了相同的查询,如果是,则从查询缓存中获取 id 列表。之后从 L2 缓存中返回与相同 ID 对应的实体。

    【讨论】:

      【解决方案3】:

      请查看下面详细解释的链接。

      查询级缓存:

      Hibernate 还实现了与二级缓存紧密集成的查询结果集缓存。

      这是一项可选功能,需要两个额外的物理缓存区域来保存缓存的查询结果和上次更新表时的时间戳。这仅对使用相同参数频繁运行的查询有用。

      二级缓存

      Hibernate 与多个二级缓存提供程序兼容。任何实现都可以用于二级缓存。

      区别:

      查询缓存的唯一目的是缓存查询,而第二缓存也可用于缓存其他缓存。

      查询缓存由 Hibernate 内部提供,而对于二级缓存,您必须选择一些外部二级缓存,例如 Infinispan、EHCache 等。

      【讨论】:

      • "二级缓存是指通过主键访问对象,即基于主键搜索整个实体,即使用 session.get()、session.load() 方法。我可以只想到上面两种方法,二级缓存就会发挥作用。”这种说法正确吗?
      • 说我有部门(可缓存实体),其中有员工集合。我怎样才能让员工也可缓存?