Hibernate的get函數

1.        從方法調用到事件處理

hibernate當中,大部分操作最終都是轉化爲事件,然後由對應的事件處理函數來處理。而事件內部主要包含的就是對Session實例的引用

2.        數據加載

數據加載主要在LoadEventListenerdoLoad()內部完成。doLoad在加載數據時,會查詢他的兩級緩存。當在緩存當中找不到時,纔會進行實際的數據庫操作。

 

2.1.       loadFromSessionCache

Session的緩存主要是指他的PersistenceContext,每次當SessionFactory要創建一個新的Session時,他都會爲其創建一個新的PersistenceContext實例。一般情況下,Session的生命週期都非常短,所以PersistenceContext作爲緩存的作用並不明顯。但是在Web開發當中,我們經常會在一個Long Conversation中重用同一個Session,此時,PersistenceContext作爲緩存的意義將會變得重要。

如果我們在PersistenceContext中找不到所需的實例,則他將會通過Session所關聯的Interceptor來獲取實例,這裏就給了我們一個繞開數據庫注入實例的機會。

 

2.1.1.      代碼

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()

 

2.2.       loadFromSecondLevelCache

如果我們在hibernate的配置文件中啓用了cache,那麼在這裏他將會查詢二級緩存。查詢Cache的過程比較簡單,首先是生成一個CacheKey,並根據這個來查詢。

 

2.2.1.      代碼

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的對象。

 

2.3.       loadFromDatasource

這是loadFromDataSource的大致流程,主要的操作都是在類UniqueEntityLoader內部完成,前半部分主要是生成JDBCPreparedStatement,並進行數據庫查詢。當結果返回以後,需要把結果先放到SessionPersistenceContext當中,這通過TwoPhaseLoadaddUninitializedEntity()postHydrate()完成。前一個方法主要是存入一個實例,該實例只設置了id屬性。後續的EntityPersister.hydrate(),用於獲取其他的屬性值,當所有屬性值獲取以後將調用postHydrate()方法更新屬性值。在存入PersistenceContext以後,要操作的就是二級緩存,這通過TwoPhaseLoad.initializeEnttiy()完成。

3.        總結:

在整個Hibernateget操作裏面,我們可以通過提供不同的Interceptor,或者直接操作他的二級緩存來改變他的整個查詢策略。

瞭解了這點,可以部分改進我們的數據庫測試。當我們的某些操作僅僅依賴於get操作時,我們可以把測試數據直接通過Interceptor或者二級緩存壓入Hiberante,而不用真正的寫入數據庫。


 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章