有人能用简单的话解释一下Hibernate/NHibernate中的一级缓存和二级缓存是什么吗?
1.1)一级缓存
一级缓存始终关联会话对象。Hibernate默认使用这个缓存。这里,它处理一个 一个接一个的交易,意味着不会处理一个交易很多 次了。主要是它减少了SQL查询的数量 在给定事务中生成。这代替了之后的更新 在事务中所做的每一次修改,都会更新事务
1.2)二级缓存
第二级缓存总是与会话工厂对象相关联。在运行事务时,在此期间它加载 对象在会话工厂级别,以便那些对象将 对整个应用程序可用,不局限于单个用户。自 对象已经加载到缓存中,无论何时对象被加载 由查询返回,当时不需要再去找数据库 事务。以这种方式,第二级缓存工作。这里我们可以用
引用自:http://javabeat.net/introduction-to-hibernate-caching/
在简化逻辑博客上有一个关于一级缓存的很好的解释。
基本上,第一级缓存发生在每个会话的基础上,而第二级缓存可以跨多个会话共享。
默认情况下,NHibernate使用基于会话对象的一级缓存。但是如果您在多服务器环境中运行,那么第一级缓存可能不太可伸缩,还会出现一些性能问题。之所以会发生这种情况,是因为由于数据分布在多个服务器上,因此必须非常频繁地访问数据库。换句话说,NHibernate提供了一个基本的、不那么复杂的进程内L1缓存。但是,它没有提供缓存解决方案必须具有的对应用程序性能有显著影响的特性。
所以所有这些问题的问题是使用与会话工厂对象相关的L2缓存。它减少了访问数据库的时间消耗,因此最终增加了应用程序的响应时间。
这里有一些hibernate缓存的基本解释…
一级缓存与" session "对象相关联。 缓存对象的范围是会话。一旦会话关闭,缓存的对象就永远消失了。 一级缓存在默认情况下是启用的,不能禁用它。 当我们第一次查询一个实体时,它会从数据库中检索出来,并存储在与hibernate会话相关的一级缓存中。 如果我们用相同的会话对象再次查询相同的对象,它将从缓存中加载,并且不会执行sql查询。 加载的实体可以使用evict()方法从会话中删除。如果该实体已使用evict()方法删除,则该实体的下一次加载将再次进行数据库调用。 整个会话缓存可以使用clear()方法删除。它将删除缓存中存储的所有实体 二级缓存与一级缓存是分开的,一级缓存可在会话工厂范围内全局使用。 二级缓存是在会话工厂范围内创建的,可以在使用该特定会话工厂创建的所有会话中使用。 这也意味着一旦会话工厂关闭,所有与之相关的缓存都会消失,缓存管理器也会关闭。 每当hibernate会话尝试加载一个实体时,它首先在第一级缓存中寻找实体的缓存副本(与特定的hibernate会话相关联)。 如果实体的缓存副本存在于第一级缓存中,它将作为load方法的结果返回。 如果在第一级缓存中没有缓存的实体,则在第二级缓存中查找缓存的实体。 如果二级缓存有缓存实体,它将作为load方法的结果返回。但是,在返回实体之前,它也存储在第一级缓存中,以便下一次调用load method for entity将从第一级缓存本身返回实体,并且不需要再次进入第二级缓存。 如果在一级缓存和二级缓存中也没有找到实体,则执行数据库查询,实体存储在两个缓存级别中,然后作为load()方法的响应返回
evict()
clear()
load()
一级缓存
会话对象保存第一级缓存数据。默认启用。第一级缓存数据将对整个应用程序不可用。一个应用程序可以使用多个会话对象。
二级缓存
SessionFactory对象保存二级缓存数据。存储在第二级缓存中的数据将对整个应用程序可用。但是我们需要显式地启用它。
Hibernate试图将持久化上下文的刷新推迟到最后可能的时刻。这种策略传统上称为事务性后台写。
write-behind与Hibernate刷新更相关,而不是任何逻辑或物理事务。在事务期间,刷新可能发生多次。
刷新的更改仅对当前数据库事务可见。在提交当前事务之前,其他并发事务看不到任何更改。
由于有了一级缓存,Hibernate可以做以下几个优化:
一个合适的缓存解决方案必须跨越多个Hibernate session,这就是Hibernate支持额外的二级缓存的原因。
二级缓存绑定到SessionFactory生命周期,因此只有在SessionFactory关闭时(通常在应用程序关闭时)才会销毁它。二级缓存主要是面向实体的,尽管它也支持可选的查询缓存解决方案。
SessionFactory
当加载一个实体时,Hibernate将执行以下操作: