(N)Hibernate 中的一级和二级缓存是啥?

Posted

技术标签:

【中文标题】(N)Hibernate 中的一级和二级缓存是啥?【英文标题】:What are the First and Second Level caches in (N)Hibernate?(N)Hibernate 中的一级和二级缓存是什么? 【发布时间】:2010-09-25 02:57:55 【问题描述】:

谁能用简单的话解释一下 Hibernate/NHibernate 中的一级和二级缓存是什么?

【问题讨论】:

【参考方案1】:

1.1) 一级缓存

一级缓存始终与Session对象相关联。 Hibernate 默认使用这个缓存。在这里,它处理一个 一个又一个的交易,意味着不会处理一个交易很多 次。主要是它减少了它需要的 SQL 查询的数量 在给定的事务中生成。那不是在之后更新 事务中完成的每一次修改,都会更新事务 仅在交易结束时。

1.2) 二级缓存

二级缓存始终与会话工厂对象相关联。在运行事务时,在它之间加载 会话工厂级别的对象,以便这些对象将 可用于整个应用程序,不绑定到单个用户。自从 对象已经加载到缓存中,只要一个对象是 查询返回的,当时不需要去数据库 交易。这样,二级缓存就起作用了。在这里我们可以使用 查询级缓存也是如此。

引用自:http://javabeat.net/introduction-to-hibernate-caching/

【讨论】:

+1 用于将一级缓存与会话对象和二级缓存与会话工厂对象映射。我什至不需要继续阅读。 一级缓存。在大多数情况下,它是不需要的,但没有办法摆脱它。但你应该一直考虑它.. @ses 在大多数情况下,您需要一级缓存。否则你会遇到非常糟糕的性能问题,比如 N+1 查询,或者没有急切的预取缓存,或者每次访问属性时都查询一次。 通常我们在很短的时间内使用会话[并且非常推荐它]/短期会话:我们甚至不使用那个缓存。如果会话长期存在,那么我们从会话中取消附加数据(例如在编辑表单时)。当我们尝试使用 query-session-api 同时为长期会话构建一些复杂的请求后请求时,似乎只需要一种情况。 @DennisCheung:链接已失效。请更新javabeat.net/introduction-to-hibernate-caching【参考方案2】:

Streamline Logic 博客上对一级缓存有很好的解释。

基本上,一级缓存发生在每个会话的基础上,而二级缓存可以在多个会话之间共享。

【讨论】:

这句话很简单,我不知道他们为什么很难解释它 呵呵......是的,我真的不知道我怎么能变得更简单:) 这实际上对我来说更清楚。第一个是每个会话,第二个是多会话,我要记住很简单。我们不能投票两次吗? :D 没有样本说明为什么需要一级缓存。至于我,在大多数情况下根本不需要它。但是您应该始终考虑它和会话。 自此答案以来已有 11 年,不幸的是,该链接现在不存在。但我在它的存档网页上找到了它的内容:web.archive.org/web/20081207044228/http://…【参考方案3】:

这里有一些关于hibernate缓存的基本解释...

一级缓存与“会话”对象相关联。 缓存对象的范围是会话。一旦会话关闭,缓存的对象就永远消失了。 一级缓存默认启用,您不能禁用它。 当我们第一次查询实体时,它会从数据库中检索并存储在与休眠会话关联的一级缓存中。 如果我们用相同的会话对象再次查询相同的对象,它将从缓存中加载,并且不会执行任何 sql 查询。 可以使用evict() 方法从会话中删除加载的实体。如果已使用evict() 方法将其删除,则该实体的下一次加载将再次进行数据库调用。 可以使用clear() 方法删除整个会话缓存。它将删除存储在缓存中的所有实体。

二级缓存不同于一级缓存,可在会话工厂范围内全局使用。 二级缓存在会话工厂范围内创建,可用于使用该特定会话工厂创建的所有会话。 这也意味着一旦会话工厂关闭,与之关联的所有缓存都会死掉,缓存管理器也会关闭。 每当休眠会话尝试加载实体时,它首先会在第一级缓存中查找实体的缓存副本(与特定休眠会话相关联)。 如果实体的缓存副本存在于一级缓存中,则作为 load 方法的结果返回。 如果一级缓存中没有缓存实体,则在二级缓存中查找缓存实体。 如果二级缓存有缓存实体,则作为 load 方法的结果返回。但是,在返回实体之前,它也存储在一级缓存中,以便下次调用实体的加载方法将从一级缓存本身返回实体,并且不需要再次进入二级缓存。 如果在一级缓存和二级缓存中也找不到实体,则执行数据库查询并将实体存储在两个缓存级别中,然后作为load()方法的响应返回。

【讨论】:

很好的解释!如果你能画一些序列图那就太棒了!!! 详尽的解释 如果您想修改您已经知道的内容,那么 Dennis C 和 Iomaxx 的上述两个答案非常棒,非常简洁且易于记忆。但是,如果您在不知道差异的情况下寻找差异的解释,那么这个答案会好得多! 很好的解释!!【参考方案4】:

一级缓存

Hibernate 尝试将持久性上下文刷新延迟到最后可能的时刻。这种策略传统上被称为事务性后写。

write-behind 与 Hibernate 刷新有关,而不是任何逻辑或物理事务。在事务期间,刷新可能会发生多次。

刷新的更改仅对当前数据库事务可见。在提交当前事务之前,其他并发事务看不到任何更改。

由于一级缓存,Hibernate可以做几处优化:

JDBC 语句批处理 防止丢失更新异常

二级缓存

一个合适的缓存解决方案必须跨越多个 Hibernate 会话,这也是 Hibernate 支持额外的二级缓存的原因。

二级缓存绑定到 SessionFactory 生命周期,所以只有在 SessionFactory 关闭时才会销毁(通常是在应用程序关闭时)。二级缓存主要是面向实体的,尽管它也支持可选的查询缓存解决方案。

加载实体时,Hibernate 会执行以下操作:

    如果实体存储在一级缓存中,则返回缓存的对象引用。这确保了应用程序级的可重复读取。 如果实体没有存储在一级缓存中并且二级缓存被激活,那么Hibernate会检查实体是否已经被缓存在二级缓存中,如果是,则将其返回给来电者。 否则,如果实体没有存储在一级或二级缓存中,则会从数据库中加载。

【讨论】:

【参考方案5】:

默认情况下,NHibernate 使用基于会话对象的第一级缓存。但是如果您在多服务器环境中运行,那么一级缓存可能不是非常具有可扩展性以及一些性能问题。发生这种情况是因为它必须非常频繁地访问数据库,因为数据分布在多个服务器上。换句话说,NHibernate 提供了一个开箱即用的基本的、不那么复杂的进程内 L1 缓存。但是,它没有提供缓存解决方案必须对应用程序性能产生显着影响的功能。

所以所有这些问题的问题是使用与会话工厂对象相关联的 L2 缓存。它减少了耗时的数据库访问,因此最终增加了应用程序的响应时间。

【讨论】:

【参考方案6】:

一级缓存

Session 对象持有一级缓存数据。默认情况下启用。第一级缓存数据不会对整个应用程序可用。一个应用程序可以使用多个会话对象。

二级缓存

SessionFactory 对象保存二级缓存数据。存储在二级缓存中的数据将可供整个应用程序使用。但我们需要明确启用它。

【讨论】:

【参考方案7】:

在二级缓存中,域 hbm 文件的键值可变,值为 false。 例如, 在这个领域类中,一天中的某些持续时间作为普遍真理保持不变。因此,它可以被标记为跨应用程序不可变。

【讨论】:

以上是关于(N)Hibernate 中的一级和二级缓存是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate中的一级缓存二级缓存和懒加载

hibernate一级和二级缓存介绍

Hibernate的一级二级缓存机制配置与测试

hibernate缓存:一级缓存和二级缓存

hibernate缓存:一级缓存和二级缓存

hibernate缓存:一级缓存和二级缓存