`
wjboy49
  • 浏览: 284700 次
  • 性别: Icon_minigender_1
  • 来自: 湖南岳阳
社区版块
存档分类
最新评论

看Hibernate源码 002 - 二级缓存

阅读更多

废话不说,今天花了一个下午的时间, 专门啃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画出来. 如果用一些工具的逆向工程, 我感觉就是喝了白开水, 看过就完事, 一点印象都没有. 不过类层次关系比较复杂, 我只好以缩略图的方式贴上来.


图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()的话题似乎总是面试的时候用人单位关心的问题. 我觉得如果能从源码的角度去分析一下, 可能更加清晰一些.

  • 大小: 104.1 KB
  • 大小: 52 KB
分享到:
评论
1 楼 yangsp1 2011-04-09  
作者:问题三的源代码你看过了没有?

请教:
     hibernate二级缓存有几种缓存策略
     1:只读型
        那么二级缓存返回的对象是只读的,不允许修改,对并发不会产生任何后果。
     2:非严格读写型
        二级缓存返回的对象即可修改也可以删除,也就是说二级缓存返回的对象没有加任何限止,并发就会出现脏读或覆盖。
     3:读写型        二级缓存返回的对象???
        防止脏读:对数据库而言,是通过日志使新查询读不到未提交的数据。
                  对二级缓存是如何实现?是每次查询都返回对象的一个深拷贝还是其它更优的办法?如果其中一个事务提交的,是不是马上更新二级缓存中的数据?
     4:事务型(可以防止脏读和不可重复读)        在上一步的基础上,如何防止不可重复读?
        二级缓存返回的是对象的引用,在对象被一个事务读取后,它如何阻止其在它事务再一次读取后不能被修改?是通过锁二级缓存的get()方法以达到当前类型的查询只能单线程执行还是有其它更优办法?


没有读过hibernate源码,想偷懒,在此直接请教。。。

相关推荐

    hibernate源码release-4.1.4.Final版

    Hibernate支持一级缓存(Session级别的缓存)和二级缓存(SessionFactory级别的缓存)。一级缓存默认开启,提高性能但需注意并发问题;二级缓存可配置第三方缓存实现,如EhCache,用于跨Session的数据共享。 五、...

    day37 05-HIbernate二级缓存:一级缓存更新同步到二级缓存及二级缓存配置文件

    本篇文章将深入探讨Hibernate的二级缓存机制,以及如何进行一级缓存与二级缓存的同步,同时还会介绍二级缓存的配置文件设置。 一级缓存是Hibernate默认提供的缓存,每个SessionFactory实例都有一个一级缓存。当对象...

    hibernate二级缓存示例源码

    综上所述,通过学习`hibernate二级缓存示例源码`,我们可以了解到如何在实际项目中配置和使用Hibernate二级缓存,从而提升系统的性能。在实际应用中,应结合具体场景选择合适的缓存策略,以达到最佳的性能优化效果。

    hibernate一级缓存、二级缓存和查询缓存

    **hibernate一级缓存、二级缓存和查询缓存** 在Java的持久化框架Hibernate中,缓存机制是提高应用程序性能的关键要素。缓存能够减少数据库的访问次数,提高数据读取速度,并且在一定程度上降低了系统的负载。本文将...

    Hibernate一级缓存和二级缓存

    标题“Hibernate一级缓存和二级缓存”指的是Hibernate框架中的两种缓存机制,它们是提高数据访问性能的关键要素。一级缓存是Session级别的,而二级缓存是SessionFactory级别的,两者在数据库操作中起到了重要的作用...

    Hibernate4二级缓存实例(源码)

    **标题解析:**“Hibernate4二级缓存实例(源码)” 这个标题表明我们将探讨一个具体的应用示例,即如何在Hibernate4框架中实现实现二级缓存,并且提供了源码供参考。Hibernate是一个流行的Java对象关系映射(ORM)...

    hibernate-release-5.2.10

    6. **缓存**:Hibernate内置了二级缓存机制,可以通过配置使用如Ehcache这样的缓存提供者,提高性能。 7. **关联映射**:包括一对一(@OneToOne)、一对多(@OneToMany)、多对一(@ManyToOne)、多对多(@...

    项目中使用 hibernate-memcached 做二级缓存

    本文将详述如何在项目中使用Hibernate与Memcached结合实现二级缓存,并探讨Memcached的基本原理和使用方法。 首先,我们需要理解什么是Hibernate的二级缓存。在Hibernate框架中,一级缓存是每个Session级别的,它...

    hibernate-core-5.0.11.Final.jar

    - 使用二级缓存提高性能,如EhCache集成。 - 合理设计实体关系,避免N+1查询问题。 - 使用批处理更新和插入,减少数据库交互次数。 通过以上分析,我们可以看出`hibernate-core-5.0.11.Final.jar`在ORM中的重要地位...

    hibernate二级缓存实例

    在Java的持久化框架Hibernate中,二级缓存是提高数据访问效率的重要机制。它是一种全局共享的、跨会话的数据存储区域,旨在减少对数据库的直接访问,从而降低系统负载,提升性能。在这个"hibernate二级缓存实例"中,...

    hibernate-orm-3.3源码

    为了提高性能,Hibernate 提供了二级缓存机制。它允许在 SessionFactory 级别共享对象,减少对数据库的访问。常用的二级缓存提供商有 EhCache 和 Infinispan。 六、懒加载与代理 Hibernate 支持懒加载(Lazy ...

    hibernate开启二级缓存和查询缓存

    在 Hibernate 中,二级缓存和查询缓存是提高应用性能的重要机制。下面将详细介绍如何开启并理解这两个缓存机制。 ### 1. 一级缓存与二级缓存 #### 1.1 一级缓存 一级缓存是 Hibernate 内置的 Session 缓存,它是每...

    hibernate-memcached-1.1.0-sources.zip

    `hibernate-memcached-1.1.0-sources.zip`提供的源码实现了一个Hibernate二级缓存提供者,它将Hibernate的查询结果缓存在Memcached中,当再次进行相同查询时,可以直接从缓存中获取数据,避免了重复的数据库查询。...

    hibernate-orm-4.3.9源码

    2. 二级缓存:SessionFactory级别的缓存,可跨Session共享,需配合缓存插件如EhCache实现。二级缓存可以提高性能,但需谨慎使用,防止数据一致性问题。 五、懒加载与立即加载 1. 懒加载:Hibernate默认的关联加载...

    Hibernat一级缓存(源码)

    3. 分布式缓存:在多节点环境中,可以考虑使用二级缓存(如 Ehcache 或 Infinispan)来实现跨节点的数据共享,提高系统性能。 总结: 一级缓存作为 Hibernate 的核心特性,极大地提高了数据访问效率。通过对源码的...

    hibernate-jpa-2.1-api-1.0.0.Final.jar

    `javax.persistence.Cache`接口则提供了二级缓存功能,提升数据访问性能。 在实际应用中,开发者可以通过实现这些接口,或者直接使用Hibernate提供的实现类,如`HibernateEntityManager`和`...

    hibernate-release-5.0.7.Final.zip

    - 缓存优化:包括二级缓存的性能提升和对查询结果的缓存支持。 4. 传智播客黑马程序员2016版框架 在传智播客黑马程序员2016年的Hibernate课程中,讲师深入讲解了如何使用5.0.7.Final版本进行实际项目开发,包括...

    day37 07-Hibernate二级缓存:查询缓存

    在IT行业中,数据库操作是...在给出的压缩包文件"hibernate3_day03"中,可能包含了与Hibernate二级缓存相关的代码示例、配置文件或者教程文档,进一步的学习和实践可以从这些资源入手,加深对二级缓存的理解和运用。

    Spring4+Hibernate4二级缓存实例源码

    通过这个"Spring4+Hibernate4二级缓存实例源码",你可以学习到如何在实际项目中结合Spring和Hibernate实现二级缓存,提高应用的运行效率。同时,深入理解缓存的工作原理和最佳实践,对于优化系统的性能和架构有着...

    Hibernate 二级缓存 总结整理

    本文将深入探讨Hibernate的二级缓存,并结合相关源码进行解析。 ### 一、一级缓存与二级缓存 1. **一级缓存(First-Level Cache)**:每个Session实例都有一个私有的、线程安全的一级缓存,它是默认开启且不可关闭...

Global site tag (gtag.js) - Google Analytics