我很难理解hibernate何时命中二级缓存以及何时使缓存无效.
这就是我目前所理解的:
二级缓存在会话之间存储实体,范围是SessionFactory
您必须告诉哪些实体要缓存,默认情况下不会缓存任何实体
查询缓存将查询结果存储在缓存中.
我不明白的是
什么时候hibernate命中这个缓存?
假设我已经设置了二级缓存,但没有设置查询缓存.我想缓存我的客户,其中有50000个.我可以通过哪些方式从缓存中检索客户?
我假设我可以通过缓存中的id获取它们.这很容易但也不值得缓存.但是,如果我想与所有客户进行一些计算,该怎么办?假设我想显示一个客户列表,然后我将如何访问它们?
如果禁用查询缓存,我将如何获得所有客户?
如果有人更新了其中一个客户,会发生什么?
该客户是否会在缓存中失效或所有客户都会失效?
或者我认为缓存完全错误?在这种情况下,哪种更适合使用二级缓存?hibernate文档根本不清楚缓存如何在现实中工作.只有如何设置它的说明.
更新: 所以我已经明白二级缓存(没有查询缓存)对于按ID加载数据会很好.例如,我有用户对象,我想检查Web应用程序中每个请求的权限.通过在二级缓存中缓存用户来减少数据库访问是否是一个好例子?就像我将用户ID存储在会话中或我需要检查权限的任何地方,我会通过它的id加载用户并检查权限.
首先,我们来谈谈进程级缓存(或者他们在Hibernate中称之为二级缓存).为了使它工作,你应该
配置缓存提供者
告诉hibernate要缓存哪些实体(如果使用这种映射,则在hbm.xml文件中).
您告诉缓存提供程序它应该存储多少个对象以及何时/为什么它们应该被无效.因此,假设您有一个Book和Author实体,每次从DB获取它们时,只会从实际DB中选择那些不在缓存中的实体.这显着提高了性能.它在以下情况下很有用:
您只能通过Hibernate写入数据库(因为它需要一种方法来知道何时更改或使缓存中的实体无效)
你经常阅读对象
您有一个节点,并且没有复制.否则,您将需要复制缓存本身(使用像JGroups这样的分布式缓存),这会增加更多的复杂性,并且它不会像无共享应用程序那样扩展.
那么什么时候缓存工作?
当您session.get()
或session.load()
先前选择的对象驻留在缓存中时.缓存是一个存储,其中ID是键,属性是值.因此,只有当有可能通过ID搜索时,您才能消除对数据库的攻击.
当您的关联延迟加载时(或者选择加入而不是加入时)
但它在以下情况下不起作用:
如果您没有按ID选择.再次- 2级缓存存储的地图实体的ID与其他性质的(它实际上并不存储对象,但数据本身),因此,如果您的查询看起来像这样:from Authors where name = :name
,那么你不打缓存.
当您使用HQL时(即使您使用where id = ?
).
如果在您设置的映射中fetch="join"
,这意味着加载关联连接将在任何地方使用,而不是单独的select语句.只有在fetch="select"
使用时,进程级缓存才对子对象起作用.
即使您已经fetch="select"
在HQL中使用连接来选择关联 - 这些连接将立即发布,它们将覆盖您在hbm.xml或注释中指定的任何内容.
现在,关于查询缓存.您应该注意,它不是一个单独的缓存,它是进程级缓存的补充.假设您有一个国家/地区实体.它是静态的,所以你知道每次你说的时候会有相同的结果集from Country
.这是查询缓存的理想选择,它将自己存储ID列表,当您下次选择所有国家/地区时,它会将此列表返回到进程级缓存,而后者又将返回每个ID的对象因为这些对象已存储在二级缓存中.每次与实体相关的任何内容发生变化时,查询缓存都会失效.因此,假设您已配置from Authors
为置于查询缓存中.由于作者经常更改,因此无效.因此,您应该仅将查询缓存用于更多或更少的静态数据.
第二级缓存是键值存储.只有通过id获取实体时它才有效
当通过hibernate更新/删除实体时,每个实体使第二级缓存无效/更新.如果以不同方式更新数据库,则不会使其无效.
对于查询(例如客户列表),使用查询缓存.
实际上,拥有一个键值分布式缓存很有用 - 这就是memcached,它支持facebook,twitter等等.但是如果你没有id的查找,那么它将不会非常有用.
晚了,但想系统地回答许多开发人员提出的问题.
在这里逐一提出你的问题是我的答案.
问:什么时候hibernate命中这个缓存?
A. 第一级缓存与Session对象相关联.该二级缓存与相关的会话工厂对象.如果在第一个中找不到对象,则检查第二个级别.
问:假设我已经设置了二级缓存,但没有设置查询缓存.我想缓存我的客户,其中有50000个.我可以通过哪些方式从缓存中检索客户?
答:您在更新中得到了答案.此外,查询缓存只存储对象的ID列表,而这些对象的ID也存储在同一个二级缓存中.因此,如果启用查询缓存,则将使用相同的资源.干得好吗?
问:我假设我可以通过缓存中的id获取它们.这很容易但也不值得缓存.但是,如果我想与所有客户进行一些计算,该怎么办?假设我想显示一个客户列表,然后我将如何访问它们?
A.上面回答.
问:如果禁用查询缓存,我将如何获得所有客户?
A.上面回答.
问:如果有人更新了其中一个客户,会发生什么?该客户是否会在缓存中失效或所有客户都会失效?
答:Hibernate不知道,但你可以使用其他第三方IMDG /分布式缓存作为hibernate二级缓存实现并使它们失效.例如,TayzGrid是一个这样的产品,我想还有更多.