我很难理解hibernate何时命中二级缓存以及何时使缓存无效。
这就是我目前所理解的:
我不明白的是
或者我认为缓存完全错误?在这种情况下,哪种更适合使用二级缓存? hibernate文档根本不清楚缓存如何在现实中工作。只有如何设置它的说明。
更新 所以我开始明白,二级缓存(没有查询缓存)可以很好地通过id加载数据。例如,我有用户对象,我想检查Web应用程序中每个请求的权限。通过在二级缓存中缓存用户来减少数据库访问是否是一个好例子?就像我将用户ID存储在会话中或我需要检查权限的任何地方,我会通过它的id加载用户并检查权限。
答案 0 :(得分:90)
首先,让我们来谈谈进程级缓存(或者在Hibernate中称之为二级缓存)。为了使它工作,你应该
告诉缓存提供程序它应该存储多少个对象以及何时/为什么它们应该被无效。因此,假设您有一个Book和Author实体,每次从DB获取它们时,只会从实际DB中选择那些不在缓存中的实体。这显着提高了性能。它在以下情况下很有用:
那么缓存何时起作用?
session.get()
或session.load()
之前选择的对象并驻留在缓存中时。缓存是一个存储,其中ID是键,属性是值。因此,只有当有可能通过ID搜索时,您才能消除对数据库的攻击。</ li>
但是在以下情况下它不起作用:
from Authors where name = :name
,那么您不会高速缓存中。where id = ?
)。 fetch="join"
,这意味着要加载关联连接将在任何地方使用,而不是单独的select语句。仅当使用fetch="select"
时,进程级缓存才对子对象起作用。fetch="select"
但是在HQL中你使用连接来选择关联 - 这些连接将立即发布,它们将覆盖你在hbm.xml或注释中指定的任何内容。现在,关于查询缓存。您应该注意,它不是一个单独的缓存,它是进程级缓存的补充。假设您有一个国家/地区实体。它是静态的,所以你知道每次当你说from Country
时会有相同的结果集。这是查询缓存的理想选择,它将自己存储 ID 列表,当您下次选择所有国家/地区时,它会将此列表返回到进程级缓存,而后者又将,将返回每个ID的对象,因为这些对象已存储在二级缓存中。
每次与实体相关的任何内容发生变化时,查询缓存都会失效。因此,假设您已将from Authors
配置为查询缓存。由于作者经常更改,因此无效。因此,您应该仅将查询缓存用于更多或更少的静态数据。
答案 1 :(得分:36)
实际上,拥有一个键值分布式缓存很有用 - 这就是memcached,它支持facebook,twitter等等。但是如果你没有id的查找,那么它就没有用了。
答案 2 :(得分:11)
晚会但想要系统地回答许多开发人员提出的问题。
在这里逐一提出你的问题是我的答案。
Q值。什么时候hibernate命中了这个缓存?
一个。 第一级缓存与会话对象相关联。 二级缓存与会话工厂对象相关联。如果在第一个中找不到对象,则检查第二个级别。
Q值。假设我已经设置了二级缓存,但没有设置查询缓存。我想缓存我的客户,其中有50000个。我可以通过哪些方式从缓存中检索客户?
一个。您在更新中得到了答案。此外,查询缓存仅存储对象的ID列表,并且这些对象w.r.t它们的ID存储在相同的二级缓存中。因此,如果启用查询缓存,则将使用相同的资源。干得好吗?
Q值。我假设我可以通过缓存中的id获取它们。这很容易但也不值得缓存。但是,如果我想与所有客户进行一些计算,该怎么办?假设我想显示一个客户列表,然后我将如何访问它们?
一个。以上回答。
Q值。如果禁用查询缓存,我将如何获得所有客户?
一个。以上回答。
Q值。如果有人更新了其中一个客户,会发生什么?该客户是否会在缓存中失效或所有客户都会失效?
一个。 Hibernate不知道,但你可以使用其他第三方IMDG /分布式缓存实现hibernate second level cache并使它们失效。例如TayzGrid就是这样一种产品,我想还有更多。
答案 3 :(得分:0)
Hibernate二级缓存在理解和实现方面有些棘手。根据您的问题,我们可以说以下话:
Hibernate何时命中此缓存?
如您所建议,仅在L1缓存之后才查询Hibernate L2缓存(如果启用;默认情况下未打开)。这是一个键值缓存,其数据跨多个会话保留。
比方说,我已经设置了二级缓存,但没有设置查询缓存。我想缓存我的客户,其中有50000。我可以通过哪些方式从缓存中检索客户?
对于此用例而言,查询缓存将是最佳选择,因为客户数据是静态的,并且是从关系数据库中检索的。
如果有人更新了一位客户,将会发生什么?该客户会在缓存中失效还是所有客户都失效?
这取决于您使用的特定Hibernate缓存策略。 Hibernate实际上有四种不同的缓存策略:
READ_ONLY :对象在缓存中不会更改。
NONSTRICT_READ_WRITE :对象(最终)在相应数据库条目更新后发生更改;这保证了最终的一致性。
READ_WRITE :对象在相应数据库条目更新后立即更改;这可以通过使用“软”锁保证强大的一致性。
交易:使用分布式XA事务更改对象,从而确保数据完整性;这样可以保证完全成功或回滚所有更改。 但是,在所有这四种情况下,更新单个数据库条目都不会使高速缓存中的整个客户列表无效。 Hibernate比这还聪明:)
要了解有关L2缓存如何在Hibernate中工作的更多信息,请查看文章“什么是Hibernate L2缓存”或深入的文章Caching in Hibernate with Redis