与此相关question
Premise:
这些是我的假设,基于我的阅读、经验和理解,它们可能是错误的,如果是,请发表评论,我将编辑问题。
- 查询缓存和二级缓存都很好
- 查询缓存缓存查询+参数的标识符结果
- 如果数据库发生更改,并且未反映到缓存中,则查询缓存存在风险
问题:
我有一个不在二级缓存中的对象。由于一些错误的编程或其他限制,加载对象的代码在同一个休眠会话中被多次调用。检索使用 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();
当我添加查询缓存时,我注意到在同一个会话期间,hibernate 不再访问数据库 N 次,每个会话只访问一次。
- 所以我的第一个假设是 Hibernate 首先在会话缓存中搜索,然后在二级缓存中搜索。这个假设正确吗?
- 我还假设如果对象(
Foo
)不在二级缓存中,在数据库中更改,然后跨会话范围的查询缓存将返回错误的标识符,从而返回错误的对象。那是对的吗?
- 那么是否可以肯定地说,即使对于非 2L 缓存对象,使用查询缓存进行包含不可变信息的查询是一个好的实践? (例如,其 where 子句包含始终返回相同结果的条件的查询,例如“select p.ser_num where p.id = ?”,当 ser_num 和 id 对一旦创建后就不会更改)
顺便说一句,在相关question据称查询缓存不适用于会话缓存范围。我是否误解了这个说法,或者其他什么?
查询缓存是一种特殊类型的二级缓存。您所说的二级缓存我更愿意称之为“对象缓存”。
对你的假设的评论:
查询缓存仅将查询的原始结果保存为主键(用 Hibernate 的话说就是 id)。它不容纳实际的水合物体。这是有道理的,因为当您使用 jdbc 执行查询时,它实际上只会在您迭代 ResultSet 时返回水合(填充)对象。该说法不一定正确。如果查询非常复杂,因此需要很长时间才能运行,那么通过使用查询缓存可以节省时间。通过使用查询缓存,您不会节省从数据库加载对象所需的时间。
- 如果数据库发生了变化,并且没有反映出来,查询缓存是有风险的
到缓存
这是事实,但它并不是查询缓存所独有的,对于您所说的二级缓存(但通常称为对象缓存)来说也是如此。
所以我的第一个假设是
Hibernate 首先在
会话缓存,然后在第二级
缓存。这个假设正确吗?
是的,加载对象时这就是行为。
我还假设如果对象 (Foo)
不在二级缓存中,
在数据库中被更改,然后
查询缓存,跨会话
范围内,将返回错误
标识符,因此错误
对象。那是对的吗?
是的,对象缓存和查询缓存都会受到影响。仅当数据库在未通过休眠状态进行更改时才需要关注。您可以通过设置查询缓存的超时来减轻这种影响。
那么可以安全地说使用
查询缓存,用于包含以下内容的查询
即使对于非 2L 也是不可变的信息
缓存对象,是一个好的做法吗?
(例如,查询其 where 子句
包含一个永远存在的条件
返回相同的结果,例如“选择
p.ser_num 其中 p.id = ?” 当 ser_num
而且id情侣一次都不会变
创建)
对于这些类型的对象,没有理由不同时使用对象缓存和查询缓存。
是的,查询缓存在会话级别(即 1 级缓存)下不起作用。这就是为什么当您再次执行查询时它会再次访问数据库的原因。它不会将查询的结果(id 集)放入会话缓存中。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)