Hibernate 查询缓存 - 对于不在二级缓存中的对象 - 有风险吗?有用?不好的做法?

标签 hibernate second-level-cache query-cache session-cache

与此相关question

前提:

这些是我的假设,基于我的阅读、经验和理解,它们可能是错误的,如果是,请发表评论,我会编辑问题。

  • 查询缓存与二级缓存一起都很好
  • 查询缓存缓存查询+参数的标识符结果
  • 如果数据库发生更改,并且未反射(reflect)到缓存中,则查询缓存存在风险

问题:

我有一个不在二级缓存中的对象。由于一些错误的编程或其他限制,加载对象的代码在同一个 hibernate session 中被多次调用。检索使用 HQL 查找查询 例如

 hibernateTemplate.find("from Foo f where f.bar > ?", bar);

在添加查询缓存之前,如果在同一个 Hibernate Session 中调用上述代码 N 次,则对数据库有 N 次命中

然后我想看看如果添加查询缓存会发生什么:

 Query query = session.createQuery("from Foo f where f.bar > ?");
 query.setCacheable(true);
 query.setParameter(bar);
 query.list();

当我添加查询缓存时,我注意到在同一个 session 期间,hibernate 不再访问数据库 N 次,每个 session 只访问一次。

  1. 所以我的第一个假设是 Hibernate 首先在 session 缓存中搜索,然后在二级缓存中搜索。这个假设正确吗?
  2. 我还假设,如果不在二级缓存中的对象(Foo)在数据库中发生了更改,那么跨 session 范围的查询缓存将返回错误的标识符,因此对象是错误的。这是正确的吗?
  3. 那么可以肯定地说,即使对于非 2L 缓存对象,使用查询缓存进行包含不可变信息的查询也是一种好的做法吗? (例如,查询的 where 子句包含始终返回相同结果的条件,例如,当 ser_num 和 id 对一旦创建后就不会更改时,“select p.ser_num where p.id = ?”)

顺便说一句,在相关question据称查询缓存不适用于 session 缓存范围。我是否误解了这个说法,或者其他什么?

最佳答案

查询缓存是一种特殊类型的二级缓存。您所说的二级缓存我更愿意称之为“对象缓存”。

对你的假设的评论:

  • Query cache is good mostly along with 2nd level cache (aka object cache).

查询缓存仅将查询的原始结果作为主键(在 Hibernate 中称为 id)保存。它不容纳实际的水合物体。这是有道理的,因为当您使用 jdbc 执行查询时,它实际上只会在您迭代 ResultSet 时返回水合(填充)对象。该说法不一定正确。如果查询非常复杂,因此需要很长时间才能运行,那么通过使用查询缓存可以节省时间。通过使用查询缓存,您不会节省从数据库加载对象所需的时间。

  • Query cache is risky if the database was changed, and it wasn't reflected to the cache

这是事实,但它并不是查询缓存所独有的,对于您所说的二级缓存(通常称为对象缓存)也是如此。

So my first assumption is that Hibernate first searches in the Session Cache, then in the 2nd Level Cache. Is this assumption correct?

是的,加载对象时就是这种行为。

I also assume that if the object (Foo) which is not in the 2nd level cache, was changed in the database, then query cache, being cross session scoped, will return the wrong identifiers, and thus the wrong objects. Is that correct?

是的,对象缓存和查询缓存都会受到影响。仅当数据库在未通过 hibernate 状态进行更改时才需要关注。您可以通过设置查询缓存的超时来减轻这种影响。

Is it then safe to say that using query cache for queries that include immutable information even for non 2L cached objects, is a good practice? (e.g. a query that its where clause contains a condition that will always return the same results, e.g. "select p.ser_num where p.id = ?" when ser_num and id couples do not change once created)

对于这些类型的对象,没有理由不同时使用对象缓存和查询缓存。

是的,查询缓存在 session 级别(即 1 级缓存)下不起作用。这就是为什么当您再次执行查询时它会再次访问数据库的原因。它不会将查询结果(id 集)放入 session 缓存中。

关于Hibernate 查询缓存 - 对于不在二级缓存中的对象 - 有风险吗?有用?不好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1998326/

相关文章:

java - hibernate 的二级 (L2) 缓存的默认实现是哪个?

mysql - query_cache_size、Qcache_total_blocks 和 query_alloc_block_size

mysql查询缓存命中率达到100%

java - 在列上使用别名的查询会出错

hibernate - 如何知道/记录查询是否使用了 Hibernate 二级缓存?

Hibernate二级缓存更新

MySQL查询缓存工作

java - Hibernate 继承映射和属性覆盖

java - 正常字段没有类型为 java.lang.String 的合格 bean 异常

Java Stream 与 JPA 一对多(LAZY)关系不起作用