众所周知,hibernate有L1和L2缓存。现在我对他们的商店有一些疑问:
更新
4。如果我有下一个代码,没有L2缓存和查询缓存:
List<Student> persons = session.createQuery("from Student").list(); List<Student> students = session.createQuery("from Student").list();
为什么hibernate会查询DB两次?它没有L1缓存,那么它只是第一次查询DB吗?
提前致谢!
答案 0 :(得分:0)
如果启用了L2缓存且L1和L2缓存中没有命中,则hibernate将查询DB。但是,从DB获取结果后,它会将结果仅存储在L2缓存中,还是存储在L1和L2中还是其他任何内容?
这完全取决于您尝试执行的操作类型
EntityManager.find()
在这种情况下,只要实体配置了@Cachable
并且启用了L2缓存,您从这些查找中收到的任何结果都将在L1和L2中缓存,并将基于您保存在L2中二级缓存配置。
EntityManager.createQuery()
在这种情况下,它不仅取决于实体是否配置了@Cachable
并且启用了L2缓存,还取决于是否通过配置全局启用查询缓存属性hibernate.cache.use_query_cache=true
或者是否指定在运行时通过query.setCachable(true)
可以缓存特定查询。
如果查询未被缓存且后续会话运行相同的查询,则不会查询L2缓存,因为查询事先不知道哪些实体标识符映射到执行查询,因此数据源必须是通过SQL查询进行咨询。
如果启用了L2缓存并且一个会话的L1有结果但L2没有,那么休眠会将此结果从L1复制到L2吗?
见上面的答案。
如果您执行了entityManager.find()
,那么如果它是一个可缓存的实体实例,则L2将使用您刚查询的实体的属性数据进行补充。
如果您执行entityManager.createQuery()
,这将取决于是否启用了查询缓存。如果未启用,则不会将任何数据复制到L2。如果启用了查询缓存,则L2将相应地更新,如上所示。
如果L2缓存启用且L2有结果但L1没有,那么休眠会将它从L2复制到L1吗?
L1高速缓存将始终具有附加实体的活动状态,无论状态是从L2高速缓存,数据存储区还是两者的组合中提取。
如果我有2&#34; session.createQuery(..)。list()&#34;在一个会话中,为什么hibernate将查询DB两次? Doens有L1缓存,然后是第二个&#34; session.createQuery(...)。list()&#34;应该从L1获得结果吗?
我将假设两个查询都执行相同的HQL语句,因为这是查询缓存适用于此用例的要求。
仅仅因为Hibernate在查询期间向数据库发出查询并不意味着不会查询或使用L2缓存。
首先,是否使用setCachable(true)
启用查询缓存的查询?
假设查询缓存和实体缓存在执行第一个list()
时为空,则hibernate会相应地填充实体和查询缓存。在第二次查询期间,它会查询L2缓存,只要实体或查询缓存都没有过期,它就会从L2中重新水合。
重要的是要注意,如果查询缓存在实体缓存结果后到期,这可能会产生一些性能瓶颈问题,因为L2查询缓存将指示要包含哪些实体,hibernate会发现它们已过期并且将会通过id重新发出每个过期实体的数据库查询。