与此question
相关前提:
这些是我的假设,根据我的阅读,经验和理解,他们可能是错的,如果是,请发表评论,我会编辑问题。
问题:
我有一个不在二级缓存中的对象。由于一些糟糕的编程或其他约束,加载对象的代码在同一个休眠会话中被多次调用。回顾是使用HQL查找查询 例如
hibernateTemplate.find("from Foo f where f.bar > ?", bar);
在添加查询缓存之前,如果上述代码在同一个Hibernate会话中被调用了N次,则会有数据库的N次点击
然后我想看看如果我添加查询缓存会发生什么:
Query query = session.createQuery("from Foo f where f.bar > ?");
query.setCacheable(true);
query.setParameter(bar);
query.list();
当我添加查询缓存时,我注意到在同一个会话期间,hibernate不会再次访问数据库N次,每次会话只能访问一次。
Foo
),那么查询缓存(跨会话范围)将返回错误的标识符,因此错误的对象。这是对的吗?顺便说一下,在相关的question中声称查询缓存不适用于会话缓存范围。我是否想念这个说法或其他什么?
答案 0 :(得分:6)
查询缓存是特定类型的二级缓存。您所谓的二级缓存我更喜欢称之为“对象缓存”。
对您的假设的评论:
- 查询缓存主要与二级缓存(又名对象)一起使用 高速缓冲存储器)。
查询缓存仅将查询的原始结果保存为主键,在hibernate中,id为。它不能容纳实际的水合物。这是有道理的,因为当您使用jdbc执行查询时,它实际上只会在您迭代ResultSet时返回水合(填充)对象。声明不一定正确。如果查询非常复杂并因此需要很长时间才能运行,那么通过使用查询缓存,您将节省该时间。您不会通过使用查询缓存来节省从数据库加载对象所需的时间。
- 如果数据库已更改,则查询缓存存在风险,并且未反映出来 到缓存
这是事实,但它并不是查询缓存所独有的,对于你所说的二级缓存也是如此,但通常称为对象缓存。
所以我的第一个假设是 Hibernate首先在中搜索 会话缓存,然后在第二级 缓存。这个假设是正确的吗?
是的,在加载对象时,这就是行为。
我还假设如果对象(Foo) 它不在二级缓存中, 然后在数据库中被更改了 查询缓存,即交叉会话 范围内,将返回错误 标识符,因此是错误的 对象。这是对的吗?
是的,对象缓存和查询缓存都会受到影响。如果在不经过休眠的情况下更改数据库,这只是一个问题。您可以通过设置查询缓存的超时来减轻这种影响。
说使用是否安全 包含查询的查询缓存 即使对于非2L也是不可变的信息 缓存对象,是一个很好的做法? (例如,查询其where子句 包含一个永远的条件 返回相同的结果,例如“选择 p.ser_num,其中p.id =?“当ser_num时 并且id夫妻不会改变一次 创建)
对于这些类型的对象,没有理由不同时使用对象缓存和查询缓存。
是的,查询缓存在会话级别也称为1级缓存不起作用。因此,当您再次执行查询时,它再次命中数据库。它不会将查询的结果(id set)放入会话缓存中。
答案 1 :(得分:2)
仅有假设 :
根据Hibernate文档中的article:
[query cache]创建两个新缓存 regions:一个持有缓存查询 结果集 (org.hibernate.cache.StandardQueryCache), 另一个持有时间戳的 最新的可查询更新 表 (org.hibernate.cache.UpdateTimestampsCache)。
我认为这意味着每当可查询表的时间戳比结果集更新时 - 它将导致hibernate在下一次调用该查询时接近数据库,并且这使得查询缓存在某些方面保持安全方面。
但是在文档的同一段后面有两句话:
应始终使用查询缓存 与二级相结合 高速缓存中。
再次,我的假设是,这是hibernate可以了解数据库的更改的唯一方法,这些更改是在此特定用户的会话之外完成的
答案 2 :(得分:1)
对于您的问题#3,我认为您不希望在未缓存对象时使用查询缓存。您将最终获得所有主要ID,但是每个键必须按一次数据库来检索对象,这些对象可能比运行查询的速度慢,而根本没有缓存。无论如何,从3.3开始,它可能在较新的版本中使用较少的查询来抓取丢失的对象,例如其中id为(:id1,:id2,...)。