废话不说,今天花了一个下午的时间, 专门啃Hibernate的二级缓存部分. Hibernate要支持好几种缓存, 那么它肯定封装了各种不同的缓存策略, 根据不同的缓存产品(如EHCache,Jboss Cache)相应处理.
我手上的源码版本是Hibernate-3.3.1GA,
按照org.hibernate.cache包里面的说明文件package.html的说明, 这个版本相比以前,
已经不再使用org.hibernate.cache.Cache/CacheProvider接口,
转而使用了org.hibernate.cache.Region/RegionFactory接口,
并且每个Region独立创建自己对缓存的访问策略. (Hibernate为每个实体类创建一个Region作为缓存区,
默认情况下使用类的全路径名做为这个Region的名称)
我个人认为, 看代码应该要带着自己的问题去跟踪, 这样才能做到线索清晰, 目的明确. Hibernate的二级缓存有实体类的缓存和集合的缓存, 下面以实体类的缓存为例, 跟踪Hibernate的二级缓存处理过程.
* 问题1
, 既然Hibernate使用二级缓存, 那么他的二级缓存是什么时候创建的?
答案很简单, 是在SessionFactoryImpl实例化的时候创建的.
org.hibernate.cache.RegionFactory有个方法 public EntityRegion
buildEntityRegion(String regionName, Properties properties,
CacheDataDescription metadata) throws CacheException; 顾名思义, 是用来创建缓存区的,
跟踪一下什么方法调用的就行.
从SessionFactoryImpl 244行开始有一段:
图1
我最初的想法是认为Hibernate在我们使用到某个类的时候(比如通过session.load(class,id)方法)才会创建缓存区并且
加载缓存对象, 这样可能更符合"懒"加载的特性. 这里我不是很明白为什么Hibernate提前初始化了这些缓存区. 不过, 实际情况中,
很多的应用都是在一开始就加载业务数据缓存, 比如角色定义, 规则, 模板等等的对象. 相对这些操作而言,
Hibernate创建缓存区并不算大的开销.(我见过某些系统初始加载耗时半个钟)
* 问题二
, Hibernate创建缓存区的时候, 里面发生了什么事情?
Hibernate的作者说"创建SessionFactory的代价非常昂贵, 而创建Session的代价很低". 此话至少前半句不假.
看上面的代码, 就知道实例化的时候创建缓存区和对应的访问策略, 如果实体类超过100个, 就要创建100个缓存区和策略,
相比创建一个Session, 确实就有些耗费不起.
我们跟踪到settings.getRegionFactory().buildEntityRegion(..)方法内部看看发生了什么.
1) buildEntityRegion() 方法
org.hibernate.cache.RegionFactory是一个接口, 它的实现类有两个.
org.hibernate.cache包的
NoCachingRegionFactory和RegionFactoryCacheProviderBridge.
NoCachingRegionFactory是一个不提供缓存的实现,
RegionFactoryCacheProviderBridge则是正常使用缓存的实现. 看它的buildEntityRegion()方法:
public EntityRegion buildEntityRegion(
String regionName,
Properties properties,
CacheDataDescription metadata) throws CacheException {
return new EntityRegionAdapter( cacheProvider.buildCache( regionName, properties ), settings, metadata );
}
很简单, 返回一个EntityRegionAdapter对象. 这个对象需要三个参数:Cache, Settings,
CacheDataDescription. Cache对象由cacheProvider.buildCache( regionName,
properties )代劳, 其他对象则是SessionFactory提供的.
此处有两个奇怪的地方, 为什么是EntityRegionAdapter? 一般而言,
adapter模式是为协调两种不同结构的对象而设计的, 其次, 这里涉及到了Cache, CacheProvider接口,
Hibernate在org.hibernate.cache包的说明里面已经声明Cache, CacheProvider接口作废. 显然,
结论只能是, Hibernate用来一套新的API替代了原来的API, 但是接口下面的实现, 仍旧依赖原来的实现!!
于是, 花点时间, 先把org.hibernate.cache包地下的类的结构搞清楚. 我的方法比较笨,
就是一个一个类去看,然后用UML画出来. 如果用一些工具的逆向工程, 我感觉就是喝了白开水, 看过就完事, 一点印象都没有.
不过类层次关系比较复杂, 我只好以缩略图的方式贴上来.
![](http://dl.iteye.com/upload/attachment/364163/a9db1b7a-69a9-35b7-b055-b701d062dd7d.jpg)
图2
很明显, Hibernate的cache源码分类五块:
第一块是访问策略, 在org.hibernate.cache.access包内. 几个类的名字很清晰的表明了意思: AccessType
-- 访问类型, read-only, read-write等. EntityRegionAccessStrategy
-- 实体类访问策略. 其实就是class的缓存访问策略. CollectionRegionAccessStrategy
-- 集合的访问策略. 其实就是class内的集合的缓存访问策略. 对象的获得都是通过这两种方式来代理给Cache对象处理的.
第二块: 代理层, 在org.hibernate.cache.impl.bridge包内. 可以见到中间有一块,
全是xxxAdapter, 分别用于代理实体, 集合, 查询结果的缓存,
透过org.hibernate.cache.CacheConcurrencyStrategy给Cache对象处理请求.
第三块: 原来的缓存实现部分. 在org.hibernate.cache包内.主要由org.hibernate.cache.CacheConcurrencyStrategy/ Cache/ CacheProvider三个接口组成.
第四块: 新的缓存API, 在org.hibernate.cache包内.包括几个主要的接口:
org.hibernate.cache.Region/ TransactionalDataRegion/ EntityRegion/
CollectionRegion/ QueryResultRegion/ RegionFactory/ CacheKey.
在CollectionRegion和EntityRegion两个类上分别创建了CollectionRegionAccessStrategy和
EntityRegionAccessStrategy.
第无块: 缓存对象入口. 在org.hibernate.cache.entry包内.
这些对象是SessionFactory和二级缓存打交道的封装. 在每个对象被放入缓存的时刻, 会被封装到一个Entry内,
透过Region来传递给真正的Cache Provider(如EHCache). 但是,
这里我们并没有看到具体的Entry从Region传递到EHCache的代码,
这个版本里已经把原来的org.hibernate.cache.EHCacheProvider分离出去了,作为一个单独的hibernate-
ehcache.jar包.
有了这个图, 缓存的结构已经很清晰了. 上面代码中的cacheProvider.buildCache( regionName,
properties ), 其实就是按照Hibernate.cfg.xml中提供的CacheProvider创建的Cache.
看一下我们很熟悉的配置
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">false</property>
对应的EHCacheProvider代码:
import net.sf.ehcache.CacheManager;
...
public class EhCacheProvider implements CacheProvider {
private CacheManager manager;
...
public Cache buildCache(String name, Properties properties) throws CacheException {
try {
net.sf.ehcache.Cache cache = manager.getCache(name);
if (cache == null) {
log.warn("Could not find configuration [" + name + "]; using defaults.");
manager.addCache(name);
cache = manager.getCache(name);
log.debug("started EHCache region: " + name);
}
return new EhCache(cache);
}
catch (net.sf.ehcache.CacheException e) {
throw new CacheException(e);
}
}
...
}
基本上, Cache接口提供的方法就是get(), put(), remove()之类的, 和java.util.Map接口类似,
另外还提供lock(), unlock()方法. 到这里, Hibernate对于实体类的缓存操作都交给EHCache去打理了.
创建好实体类缓存区后, 谁来和它打交道呢? 答案就是EntityRegionAccessStrategy. 类层次结构见上图2.
从图1中就能发现, SessionFactoryImpl在创建好缓存区后,
就开始使用EntityRegion.buildAccessStrategy()方法创建EntityRegionAccessStrategy.
2) buildAccessStrategy
() 方法
我们已经知道对应EntityRegion接口的实现类是EntityRegionAdapter, 看看它的代码, 很简单
public class EntityRegionAdapter
extends BaseTransactionalDataRegionAdapter implements EntityRegion {
private static final Logger log = LoggerFactory.getLogger( EntityRegionAdapter.class );
public EntityRegionAdapter(Cache underlyingCache, Settings settings, CacheDataDescription metadata) {
super( underlyingCache, settings, metadata );
if ( underlyingCache instanceof OptimisticCache ) {
( ( OptimisticCache ) underlyingCache ).setSource( new OptimisticCacheSourceAdapter( metadata ) );
}
}
public EntityRegionAccessStrategy buildAccessStrategy
(AccessType accessType) throws CacheException {
CacheConcurrencyStrategy ccs;
if ( AccessType.READ_ONLY.equals( accessType ) ) {
if ( metadata.isMutable() ) {
log.warn( "read-only cache configured for mutable entity [" + getName() + "]" );
}
ccs
= new ReadOnlyCache();
}
else if ( AccessType.READ_WRITE.equals( accessType ) ) {
ccs
= new ReadWriteCache();
}
else if ( AccessType.NONSTRICT_READ_WRITE.equals( accessType ) ) {
ccs
= new NonstrictReadWriteCache();
}
else if ( AccessType.TRANSACTIONAL.equals( accessType ) ) {
ccs
= new TransactionalCache();
}
else {
throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" );
}
ccs.setCache( underlyingCache );
return new EntityAccessStrategyAdapter
( this, ccs, settings );
}
}
好戏发生在最后一行代码, 生成一个EntityAccessStrategyAdapter对象,
并由它去处理一个CacheConcurrencyStrategy , 而且CacheConcurrencyStrategy
包含了刚刚创建的Cache(其实就是EHCache对象).
这里的accessType对应着我们在xxx.hbm.xml中定义的<cache>元素, 例如
<hibernate-mapping package="work">
<class name="Comment" lazy="false">
<cache usage="read-write"/>
...
</hibernate-mapping>
* 问题三
. 当我们使用session去对实体类操作的时候, 二级缓存的部分发生了什么事情? 比如session.load(), session.get(), session.save(), session.delete(), session.evit()等方法
session.load(), session.get()的话题似乎总是面试的时候用人单位关心的问题. 我觉得如果能从源码的角度去分析一下, 可能更加清晰一些.
![点击查看原始大小图片](http://dl2.iteye.com/upload/attachment/0036/4161/3595b30d-b312-3d60-a8bb-910b8ad0656e-thumb.jpg)
- 大小: 104.1 KB
![点击查看原始大小图片](http://dl2.iteye.com/upload/attachment/0036/4163/a9db1b7a-69a9-35b7-b055-b701d062dd7d-thumb.jpg)
- 大小: 52 KB
分享到:
相关推荐
Hibernate支持一级缓存(Session级别的缓存)和二级缓存(SessionFactory级别的缓存)。一级缓存默认开启,提高性能但需注意并发问题;二级缓存可配置第三方缓存实现,如EhCache,用于跨Session的数据共享。 五、...
本篇文章将深入探讨Hibernate的二级缓存机制,以及如何进行一级缓存与二级缓存的同步,同时还会介绍二级缓存的配置文件设置。 一级缓存是Hibernate默认提供的缓存,每个SessionFactory实例都有一个一级缓存。当对象...
综上所述,通过学习`hibernate二级缓存示例源码`,我们可以了解到如何在实际项目中配置和使用Hibernate二级缓存,从而提升系统的性能。在实际应用中,应结合具体场景选择合适的缓存策略,以达到最佳的性能优化效果。
**hibernate一级缓存、二级缓存和查询缓存** 在Java的持久化框架Hibernate中,缓存机制是提高应用程序性能的关键要素。缓存能够减少数据库的访问次数,提高数据读取速度,并且在一定程度上降低了系统的负载。本文将...
标题“Hibernate一级缓存和二级缓存”指的是Hibernate框架中的两种缓存机制,它们是提高数据访问性能的关键要素。一级缓存是Session级别的,而二级缓存是SessionFactory级别的,两者在数据库操作中起到了重要的作用...
**标题解析:**“Hibernate4二级缓存实例(源码)” 这个标题表明我们将探讨一个具体的应用示例,即如何在Hibernate4框架中实现实现二级缓存,并且提供了源码供参考。Hibernate是一个流行的Java对象关系映射(ORM)...
6. **缓存**:Hibernate内置了二级缓存机制,可以通过配置使用如Ehcache这样的缓存提供者,提高性能。 7. **关联映射**:包括一对一(@OneToOne)、一对多(@OneToMany)、多对一(@ManyToOne)、多对多(@...
本文将详述如何在项目中使用Hibernate与Memcached结合实现二级缓存,并探讨Memcached的基本原理和使用方法。 首先,我们需要理解什么是Hibernate的二级缓存。在Hibernate框架中,一级缓存是每个Session级别的,它...
- 使用二级缓存提高性能,如EhCache集成。 - 合理设计实体关系,避免N+1查询问题。 - 使用批处理更新和插入,减少数据库交互次数。 通过以上分析,我们可以看出`hibernate-core-5.0.11.Final.jar`在ORM中的重要地位...
在Java的持久化框架Hibernate中,二级缓存是提高数据访问效率的重要机制。它是一种全局共享的、跨会话的数据存储区域,旨在减少对数据库的直接访问,从而降低系统负载,提升性能。在这个"hibernate二级缓存实例"中,...
为了提高性能,Hibernate 提供了二级缓存机制。它允许在 SessionFactory 级别共享对象,减少对数据库的访问。常用的二级缓存提供商有 EhCache 和 Infinispan。 六、懒加载与代理 Hibernate 支持懒加载(Lazy ...
在 Hibernate 中,二级缓存和查询缓存是提高应用性能的重要机制。下面将详细介绍如何开启并理解这两个缓存机制。 ### 1. 一级缓存与二级缓存 #### 1.1 一级缓存 一级缓存是 Hibernate 内置的 Session 缓存,它是每...
`hibernate-memcached-1.1.0-sources.zip`提供的源码实现了一个Hibernate二级缓存提供者,它将Hibernate的查询结果缓存在Memcached中,当再次进行相同查询时,可以直接从缓存中获取数据,避免了重复的数据库查询。...
2. 二级缓存:SessionFactory级别的缓存,可跨Session共享,需配合缓存插件如EhCache实现。二级缓存可以提高性能,但需谨慎使用,防止数据一致性问题。 五、懒加载与立即加载 1. 懒加载:Hibernate默认的关联加载...
3. 分布式缓存:在多节点环境中,可以考虑使用二级缓存(如 Ehcache 或 Infinispan)来实现跨节点的数据共享,提高系统性能。 总结: 一级缓存作为 Hibernate 的核心特性,极大地提高了数据访问效率。通过对源码的...
`javax.persistence.Cache`接口则提供了二级缓存功能,提升数据访问性能。 在实际应用中,开发者可以通过实现这些接口,或者直接使用Hibernate提供的实现类,如`HibernateEntityManager`和`...
- 缓存优化:包括二级缓存的性能提升和对查询结果的缓存支持。 4. 传智播客黑马程序员2016版框架 在传智播客黑马程序员2016年的Hibernate课程中,讲师深入讲解了如何使用5.0.7.Final版本进行实际项目开发,包括...
在IT行业中,数据库操作是...在给出的压缩包文件"hibernate3_day03"中,可能包含了与Hibernate二级缓存相关的代码示例、配置文件或者教程文档,进一步的学习和实践可以从这些资源入手,加深对二级缓存的理解和运用。
通过这个"Spring4+Hibernate4二级缓存实例源码",你可以学习到如何在实际项目中结合Spring和Hibernate实现二级缓存,提高应用的运行效率。同时,深入理解缓存的工作原理和最佳实践,对于优化系统的性能和架构有着...
本文将深入探讨Hibernate的二级缓存,并结合相关源码进行解析。 ### 一、一级缓存与二级缓存 1. **一级缓存(First-Level Cache)**:每个Session实例都有一个私有的、线程安全的一级缓存,它是默认开启且不可关闭...