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

发布于 2024-08-16 08:07:25 字数 1341 浏览 11 评论 0 原文

与此问题相关

前提:

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

  • 查询缓存主要与二级缓存一起使用,
  • 查询缓存缓存查询+参数的标识符结果,
  • 如果数据库发生更改,查询缓存是有风险的,并且它没有反映到缓存

问题:

我有不在二级缓存中的对象。由于一些错误的编程或其他限制,加载对象的代码在同一个休眠会话中被多次调用。检索使用 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 次,每个会话只访问一次。

  1. 所以我的第一个假设是 Hibernate 首先在会话缓存中搜索,然后在二级缓存中搜索。这个假设正确吗?
  2. 我还假设,如果不在二级缓存中的对象(Foo)在数据库中发生了更改,那么跨会话范围的查询缓存将返回错误的标识符,因此错误的对象。这是正确的吗?
  3. 那么是否可以肯定地说,即使对于非 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.

  1. So my first assumption is that Hibernate first searches in the Session Cache, then in the 2nd Level Cache. Is this assumption correct?
  2. 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?
  3. 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一曲爱恨情仇 2024-08-23 08:07:25

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

对你的假设的评论:

  • 查询缓存与二级缓存(又名对象
    缓存)。

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

  • 如果数据库发生更改并且未反映出来,查询缓存就会存在风险
    到缓存

来说也是如此。

所以我的第一个假设是
Hibernate 首先在
会话缓存,然后在第二级
缓存。这个假设正确吗?

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

我还假设如果对象 (Foo)
不在二级缓存中,
在数据库中被更改,然后
查询缓存,跨会话
范围内,将返回错误
标识符,因此错误
对象。这是正确的吗?

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

那么可以安全地说使用
查询缓存,用于包含以下内容的查询
即使对于非 2L 也是不可变的信息
缓存对象,是一个好的做法吗?
(例如,查询其 where 子句
包含一个永远存在的条件
返回相同的结果,例如“选择
p.ser_num 其中 p.id = ?” 当 ser_num
而且id情侣一次都不会变
创建)

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

是的,查询缓存在会话级别(即 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:

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

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.

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

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.

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

Yes, when loading objects this is the behaviour.

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?

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.

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)

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.

‖放下 2024-08-23 08:07:25

仅假设

根据此文章

[查询缓存]创建两个新缓存
区域:一个保存缓存查询的区域
结果集
(org.hibernate.cache.StandardQueryCache),
其他持有时间戳
可查询的最新更新
桌子
(org.hibernate.cache.UpdateTimestampsCache)。

我认为这意味着每当可查询表的时间戳比结果集新时 - 它都会导致 hibernate 在该查询的下一次调用中接近数据库,并且在某些方面保持查询缓存的安全。

但在文档的同一段后面有两句话说:

应始终使用查询缓存
与二级相结合
缓存。

再次,我的假设是,这是 hibernate 能够了解在该特定用户会话中完成的数据库更改的唯一方法

only assumptions:

According to this article from Hibernate documentation:

[query cache] creates two new cache
regions: one holding cached query
result sets
(org.hibernate.cache.StandardQueryCache),
the other holding timestamps of the
most recent updates to queryable
tables
(org.hibernate.cache.UpdateTimestampsCache).

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:

The query cache should always be used
in conjunction with the second-level
cache.

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

妥活 2024-08-23 08:07:25

对于您的问题#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,...).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文