`
catalin
  • 浏览: 16131 次
  • 来自: ...
社区版块
存档分类
最新评论

Hibernate经典问题收集1-Lazy Loading (Load&Get)

阅读更多

http://www.iteye.com/topic/491288

Hibernate的get函数

<script type="text/javascript"></script><script type="text/javascript"></script>

<!--[if !supportLists]-->1.        <!--[endif]-->从方法调用到事件处理

hibernate当中,大部分操作最终都是转化为事件,然后由对应的事件处理函数来处理。而事件内部主要包含的就是对Session实例的引用

<!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->2.        <!--[endif]-->数据加载

数据加载主要在LoadEventListenerdoLoad()内部完成。doLoad在加载数据时,会查询他的两级缓存。当在缓存当中找不到时,才会进行实际的数据库操作。

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->2.1.       <!--[endif]-->loadFromSessionCache

Session的缓存主要是指他的PersistenceContext,每次当SessionFactory要创建一个新的Session时,他都会为其创建一个新的PersistenceContext实例。一般情况下,Session的生命周期都非常短,所以PersistenceContext作为缓存的作用并不明显。但是在Web开发当中,我们经常会在一个Long Conversation中重用同一个Session,此时,PersistenceContext作为缓存的意义将会变得重要。

如果我们在PersistenceContext中找不到所需的实例,则他将会通过Session所关联的Interceptor来获取实例,这里就给了我们一个绕开数据库注入实例的机会。

 

<!--[if !supportLists]-->2.1.1.      <!--[endif]-->代码

public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {

final Object result = persistenceContext.getEntity(key);

if ( result == null ) {

     final Object newObject = interceptor.getEntity( key.getEntityName(), key.getIdentifier() );           if ( newObject != null ) {

lock( newObject, LockMode.NONE );

}

return newObject;

}else {

return result;

}

}

 

     注:这段代码是主要的数据加载部分,从代码可以看到在加载数据时,首先调用的是

         persistenceContext.getEntity(),当失败时则调用interceptor.getEntity()

 

<!--[if !supportLists]-->2.2.       <!--[endif]-->loadFromSecondLevelCache

如果我们在hibernate的配置文件中启用了cache,那么在这里他将会查询二级缓存。查询Cache的过程比较简单,首先是生成一个CacheKey,并根据这个来查询。

 

<!--[if !supportLists]-->2.2.1.      <!--[endif]-->代码

protected Object loadFromSecondLevelCache(

              final LoadEvent event,

              final EntityPersister persister,

              final LoadEventListener.LoadType options) throws HibernateException {

        

         final SessionImplementor source = event.getSession();

        

         final boolean useCache = persister.hasCache() &&

              source.getCacheMode().isGetEnabled() &&

              event.getLockMode().lessThan(LockMode.READ);

        

         if (useCache) {

              final SessionFactoryImplementor factory = source.getFactory();           

              final CacheKey ck = new CacheKey(

                       event.getEntityId(),

                       persister.getIdentifierType(),

                       persister.getRootEntityName(),

                       source.getEntityMode(),

                       source.getFactory()

                   );

              Object ce = persister.getCache()

                   .get( ck, source.getTimestamp() );

              ……

              if ( ce != null ) {

                   CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure()

                            .destructure(ce, factory);

                   // Entity was found in second-level cache...

                   return assembleCacheEntry(

                            entry,

                            event.getEntityId(),

                            persister,

                            event

                       );

              }

         }       

         return null;

     }

 

注:在操作二级缓存时,Hibernate并不是直接使用ObjectID或者hashCode来作为Key,而是使用一个自

定义的CacheKey类。而所存储的对象也不仅仅是实体本身,而是一个经过assemble的对象。

 

<!--[if !supportLists]-->2.3.       <!--[endif]-->loadFromDatasource

这是loadFromDataSource的大致流程,主要的操作都是在类UniqueEntityLoader内部完成,前半部分主要是生成JDBCPreparedStatement,并进行数据库查询。当结果返回以后,需要把结果先放到SessionPersistenceContext当中,这通过TwoPhaseLoadaddUninitializedEntity()postHydrate()完成。前一个方法主要是存入一个实例,该实例只设置了id属性。后续的EntityPersister.hydrate(),用于获取其他的属性值,当所有属性值获取以后将调用postHydrate()方法更新属性值。在存入PersistenceContext以后,要操作的就是二级缓存,这通过TwoPhaseLoad.initializeEnttiy()完成。

<!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->3.        <!--[endif]-->总结:

在整个Hibernateget操作里面,我们可以通过提供不同的Interceptor,或者直接操作他的二级缓存来改变他的整个查询策略。

了解了这点,可以部分改进我们的数据库测试。当我们的某些操作仅仅依赖于get操作时,我们可以把测试数据直接通过Interceptor或者二级缓存压入Hiberante,而不用真正的写入数据库。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics