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

Era*_*dan 10 hibernate second-level-cache session-cache query-cache

与此问题相关

前提:

这些是我的假设,根据我的阅读,经验和理解,他们可能是错的,如果他们是,请评论,我会编辑问题.

  • 查询缓存主要与二级缓存一起使用
  • 查询缓存缓存查询+参数的标识符结果
  • 如果数据库已更改,则查询缓存存在风险,并且未将其反映到缓存中

题:

我有一个不在二级缓存中的对象.由于一些糟糕的编程或其他约束,加载对象的代码在同一个休眠会话中被多次调用.回顾是使用HQL查找查询,例如

 hibernateTemplate.find("from Foo f where f.bar > ?", bar);
Run Code Online (Sandbox Code Playgroud)

在添加查询缓存之前,如果上述代码在同一个Hibernate会话中被调用了N次,那么数据库就会有N次命中

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

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

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

  1. 所以我的第一个假设是Hibernate首先在Session Cache中搜索,然后在2nd Level Cache中搜索.这个假设是否正确?
  2. 我还假设如果Foo不在第二级缓存中的object()在数据库中被更改,那么查询缓存(跨会话范围)将返回错误的标识符,从而返回错误的对象.那是对的吗?
  3. 那么,对于包含不可变信息的查询,即使对于非2L缓存对象,使用查询缓存是否安全可行?(例如,其where子句包含将始终返回相同结果的条件的查询,例如,当ser_num和id对在创建后不更改时,"select p.ser_num where p.id =?")

顺便说一下,在相关问题中声称查询缓存不适用于会话缓存范围.我想知道这个说法或其他什么吗?

Mic*_*les 7

查询缓存是特定类型的二级缓存.您所谓的二级缓存我更喜欢称之为"对象缓存".

评论你的假设:

  • 查询缓存主要与二级缓存(又称对象缓存)一起使用.

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

  • 如果数据库已更改,则查询缓存存在风险,并且未将其反映到缓存中

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

所以我的第一个假设是Hibernate首先在Session Cache中搜索,然后在2nd Level Cache中搜索.这个假设是否正确?

是的,在加载对象时,这就是行为.

我还假设如果在数据库中更改了不在第二级缓存中的对象(Foo),那么查询缓存(跨会话范围)将返回错误的标识符,从而返回错误的对象.那是对的吗?

是的,对象缓存和查询缓存都会受到影响.如果在不经过休眠的情况下更改数据库,这只是一个问题.您可以通过设置查询缓存的超时来减轻此影响.

那么,对于包含不可变信息的查询,即使对于非2L缓存对象,使用查询缓存是否安全可行?(例如,其where子句包含将始终返回相同结果的条件的查询,例如,当ser_num和id对在创建后不更改时,"select p.ser_num where p.id =?")

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

是的,查询缓存在会话级别也称为1级缓存不起作用.因此,当您再次执行查询时,它再次命中数据库.它不会将查询的结果(id set)放入会话缓存中.