与此问题相关
前提:
这些是我的假设,基于我的阅读、经验和理解,它们可能是错误的,如果是,请发表评论,我会编辑问题。
- 查询缓存主要与二级缓存一起使用,
- 查询缓存缓存查询+参数的标识符结果,
- 如果数据库发生更改,查询缓存是有风险的,并且它没有反映到缓存
问题:
我有不在二级缓存中的对象。由于一些错误的编程或其他限制,加载对象的代码在同一个休眠会话中被多次调用。检索使用 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 次,每个会话只访问一次。
- 所以我的第一个假设是 Hibernate 首先在会话缓存中搜索,然后在二级缓存中搜索。这个假设正确吗?
- 我还假设,如果不在二级缓存中的对象(
Foo
)在数据库中发生了更改,那么跨会话范围的查询缓存将返回错误的标识符,因此错误的对象。这是正确的吗?
- 那么是否可以肯定地说,即使对于非 2L 缓存对象,使用查询缓存进行包含不可变信息的查询是一个好的实践? (例如,一个查询,其where子句包含一个总是返回相同结果的条件,例如“select p.ser_num where p.id = ?”,当ser_num和id对一旦创建后就不会改变)
顺便说一下,在相关的声称的问题该查询缓存不适用于会话缓存范围。我是否误解了这个说法,或者其他什么?
Related to this question
Premise:
These are my assumptions, based on my reading, experience and understanding, they may be wrong, if they are, please comment and I'll edit the question.
- Query cache is good mostly along with 2nd level cache
- Query cache caches the identifiers results of queries + parameters
- Query cache is risky if the database was changed, and it wasn't reflected to the cache
Question:
I have an object that is not in the 2nd level cache. Due to some bad programming or other constraints, the code that loads the object is being called several time in the same hibernate session. The retrival is using an HQL find query
e.g.
hibernateTemplate.find("from Foo f where f.bar > ?", bar);
Before adding query cache, if the above code was called N times within the same Hibernate Session, there were N hits to the database
Then I wanted to see what happens if I add query cache:
Query query = session.createQuery("from Foo f where f.bar > ?");
query.setCacheable(true);
query.setParameter(bar);
query.list();
When I added query cache, i've noticed that during the same session, hibernate doesn't hit the database N times anymore, only once per session.
- 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?
- 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)
By the way, in the related question it is claimed that query cache doesn't work on the Session Cache scope. Am I missunderstanding that claim, or anything else?
发布评论
评论(3)
查询缓存是一种特殊类型的二级缓存。您所说的二级缓存我更愿意称之为“对象缓存”。
对你的假设的评论:
查询缓存仅将查询的原始结果作为主键(在 Hibernate 中称为 id)保存 它不容纳实际的水合物体。这是有道理的,因为当您使用 jdbc 执行查询时,它实际上只会在您迭代 ResultSet 时返回水合(填充)对象。该说法不一定正确。如果查询非常复杂,因此需要很长时间才能运行,那么通过使用查询缓存可以节省时间。通过使用查询缓存,您不会节省从数据库加载对象所需的时间。
来说也是如此。
是的,加载对象时这就是行为。
是的,对象缓存和查询缓存都会受到影响。仅当数据库在未通过休眠状态进行更改时才需要关注。您可以通过设置查询缓存的超时来减轻这种影响。
对于这些类型的对象,没有理由不同时使用对象缓存和查询缓存。
是的,查询缓存在会话级别(即 1 级缓存)下不起作用。这就是为什么当您再次执行查询时它会再次访问数据库的原因。它不会将查询结果(id 集)放入会话缓存中。
A query cache is a particular type of 2nd level cache. What you refer to as 2nd level cache I'd prefer to call "object cache".
Comments on your assumptions:
A query cache only holds the raw results of the queries as primary keys, in hibernate speak, id's. It does not hold the actual hydrated objects. This makes sense as when you execute a query with jdbc it only actually gives you back hydrated (populated) objects as you iterate over the ResultSet. The statement is not necessarily correct. If the query is very complicated and thus takes a very long time to run, by using a query cache you will save that time. You will not, by using a query cache, save the time it takes to load the objects from the database.
This is true, but it is not unique to query cache, the same holds true for what you term 2nd level cache, but what is typically called object cache.
Yes, when loading objects this is the behaviour.
Yes, both the object cache and the query cache will be affected. This is only of concern if the database is changed without going via hibernate. You can potentially mitigate the effect of this by setting the timeout of the query cache.
For these kind of objects there's no reason not to use both an object cache and a query cache.
And yes, query cache does not work at session level aka Level 1 cache. Thus the reason why when you execute the query again it hits the database again. It will not put the result (id set) of a query into the session cache.
仅假设:
根据此文章:
我认为这意味着每当可查询表的时间戳比结果集新时 - 它都会导致 hibernate 在该查询的下一次调用中接近数据库,并且在某些方面保持查询缓存的安全。
但在文档的同一段后面有两句话说:
再次,我的假设是,这是 hibernate 能够了解在该特定用户会话中完成的数据库更改的唯一方法
only assumptions:
According to this article from Hibernate documentation:
I assume this means that whenever the timestamp of the queryable table is newer than the result-set - it will cause hibernate to approach the DB in the the next call for that query, and that what keep the query cache safe in some aspect.
But 2 sentences later in the same paragraph of the documentation it says:
again, my assumption is that this is the only way hibernate can be aware of changes to the database that are done out of this specific user's session
对于您的问题#3,我认为您不想在未缓存对象时使用查询缓存。您最终将获得所有主 ID,但每个键都必须访问数据库一次才能检索对象,这可能比在根本没有缓存的情况下运行查询要慢。无论如何,从 3.3 开始,也许在较新的版本中,它会使用更少的查询来获取丢失的对象,例如 where id in (:id1,:id2,...)。
For your question #3, I don't think you want to use the query cache when the objects aren't cached. You'll end up with all the primary ids but it will have to hit the database once per key to retrieve the objects which may be slower than running the query with no caching at all. As of 3.3 anyway, maybe in newer versions it grabs the missing objects using fewer queries, e.g. where id in (:id1,:id2,...).