我很难理解休眠何时命中二级缓存以及何时使缓存失效。
目前我的理解是这样的:
- 二级缓存存储会话之间的实体,范围是SessionFactory
- 您必须告诉要缓存哪些实体,默认情况下不会缓存任何实体
- 查询缓存将查询结果存储在缓存中。
我不明白的是
- hibernate什么时候命中这个缓存?
- 假设我设置了二级缓存,但没有设置查询缓存。我想缓存我的客户,有 50000 个。我可以通过哪些方式从缓存中检索客户?
- 我假设我可以通过 id 从缓存中获取它们。这很容易,但也不值得缓存。但是如果我想对所有客户进行一些计算该怎么办?假设我想显示客户列表,那么我该如何访问他们呢?
- 如果禁用查询缓存,我将如何获得所有客户?
- What would happen if someone updated one of the customers?
或者我认为缓存完全错误?在这种情况下,二级缓存的更合适用途是什么? hibernate 文档根本不清楚缓存实际上是如何工作的。仅提供有关如何设置的说明。
Update:所以我开始明白二级缓存(没有查询缓存)对于通过 id 加载数据很有好处。例如,我有一个用户对象,我想检查 Web 应用程序中每个请求的权限。这是通过将用户缓存在二级缓存中来减少数据库访问的好案例吗?就像我将用户 ID 存储在会话中或任何地方,当我需要检查权限时,我会按用户 ID 加载用户并检查权限。
首先,我们来谈谈进程级缓存(或者在 Hibernate 中称为二级缓存)。为了让它发挥作用,你应该
- 配置缓存提供者
- 告诉 hibernate 要缓存哪些实体(如果使用这种映射,就在 hbm.xml 文件中)。
您告诉缓存提供程序应存储多少对象以及它们何时/为何应失效。假设您有一本书和一个作者实体,每次您从数据库获取它们时,只有那些不在缓存中的实体才会从实际数据库中选择。这显着提高了性能。它在以下情况下很有用:
- 您只能通过 Hibernate 写入数据库(因为它需要一种方法来知道何时更改或使缓存中的实体无效)
- 你经常阅读物体
- 您只有一个节点,并且没有复制。否则,您需要复制缓存本身(使用像 JGroups 这样的分布式缓存),这会增加更多的复杂性,并且它的扩展性不如不共享应用程序。
那么缓存什么时候起作用呢?
- 当你
session.get()
or session.load()
先前选择并驻留在缓存中的对象。缓存是一种存储,其中 ID 是键,属性是值。因此,只有当可以通过 ID 进行搜索时,您才能消除对数据库的访问。
- 当您的关联是延迟加载的(或使用选择而不是连接进行急切加载)时
但在以下情况下它不起作用:
- 如果不按ID选择。同样,二级缓存存储实体 ID 到其他属性的映射(它实际上并不存储对象,而是数据本身),因此如果您的查找如下所示:
from Authors where name = :name
,那么你就不会命中缓存。
- 当你使用 HQL 时(即使你使用
where id = ?
).
- 如果在您的映射中设置
fetch="join"
,这意味着要加载关联,连接将在任何地方使用,而不是单独的选择语句。进程级缓存仅在以下情况下才适用于子对象:fetch="select"
用来。
- 即使你有
fetch="select"
但随后在 HQL 中,您使用联接来选择关联 - 这些联接将立即发出,并且它们将覆盖您在 hbm.xml 或注释中指定的任何内容。
现在,关于查询缓存。您应该注意,它不是一个单独的缓存,而是对进程级缓存的补充。假设您有一个 Country 实体。它是静态的,所以你知道每次当你说时都会有相同的结果集from Country
。这是查询缓存的完美候选者,它将存储一个列表IDs当您下次选择所有国家/地区时,它将将此列表返回到进程级缓存,而后者又将返回每个 ID 的对象,因为这些对象已存储在二级缓存中。
每次与实体相关的任何内容发生更改时,查询缓存都会失效。假设您配置了from Authors
被放入查询缓存中。由于作者经常更换,因此不会有效。因此,您应该仅对或多或少的静态数据使用查询缓存。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)