1. 程式人生 > >hibernate3 二級快取一些注意的地方

hibernate3 二級快取一些注意的地方

  1.Hibernate3的二級快取和session級別的快取一樣都只對實體物件做快取,不對屬性級別的查詢做快取;二級快取的生命週期和sessionFactory的生命週期是一樣的,sessionFactory可以管理二級快取;

    2.sessionFactory級別的快取,需要手動配置;所有的session可以共享sessionFactory 級別的快取;(一般把一些不經常變化的實體物件放到sessionFactory級別的快取中,適合放不經常變化的實體物件。)

    3.Hiberante3二級快取的配置和使用方法如下:

    必須把ehcache.jar包匯入,然後到Hibernate3.2的etc檔案下把ehcache.xml複製到工程src目錄下(ehcache.xml裡邊的引數裡邊有詳細英文說明);

    說明:ehcache.jar是第三方法的快取產品,hiberante只是把它做了整合,還有好多第三方hibernate整合的快取產品,相關說明請查閱hiberante3開發手冊;ehcache是不支援分佈應用的,如果有分散式需求,請換成支援分散式的二級快取產品,hiberate3開發手冊都有相頭說明。配置方法都類似);

    4.Hibernate3的二級快取預設是開起的,也可以指定開起。在hibernate.cfg.xml 檔案下配置如下:

    *修改hibernate.cfg.xml檔案,開戶二級快取;

要讓那些實體使用二級快取,在hibernate.cfg.xml配置檔案中加入:

Read-only一般使用這個策略,其它的hibernate3開發手冊中也有詳細介紹;

    CacheMode去hibernate3開發手冊中搜索這個關鍵字,可以找到一級快取和二級快取互動使用的問題。

1.Session 級別的快取,它同

session邦定。它的生命週期和session相同。Session消毀,它也同時消毀;管理一級快取,一級快取無法取消,用兩個方法管理,clear(),evict()

2.兩個session 不能共享一級快取,因它會伴隨session的生命週期的建立和消毀;

3.Session快取是實體級別的快取,就是隻有在查詢物件級別的時候才使用,如果

使用HQLSQL是查詢屬性級別的,是不使用一級快取的!切記!!!!

4 .  iterate 查詢使用快取,會發出查詢IdSQLHQL語句,但不會發出查實體的,

它查詢完會把相應的實體放到快取裡邊,一些實體查詢如果快取裡邊有,就從快取中查詢,但還是會發出查詢idSQLHQL語句。如果快取中沒有它會資料庫中查詢,然後將查詢到的實體一個一個放到快取中去,所以會有N+1問題出現。

5 . List()iterate 查詢區別:

使用iterate,list查詢實體物件*N+1問題,在預設情況下,使用query.iterate查詢,有可以能出現N+1問題

所謂的N+1是在查詢的時候發出了N+1條sql語句1:首先發出一條查詢物件id列表的sqlN:

根據id列表到快取中查詢,如果快取中不存在與之匹配的資料,那麼會根據id發出相應的sql語句list和iterate的區別?

list每次都會發出sql語句,list會向快取中放入資料,而不利用快取中的資料

iterate:在預設情況下iterate利用快取資料,但如果快取中不存在資料有可以能出現N+1問題

6.Get()和load(),iterate方法都會使用一級快取. 

7.  hiberate3 session 儲存過程如下:

       例如 object 物件

       Session.save(object);

       這時候不會把資料放到資料庫,會先放到session快取中去,資料庫中沒有相應記錄,session.flush();才發SQL和HQL語句,資料庫中有了相應記錄,

       但是資料庫用select查不到,這是跟資料庫事物級別有關係,(這裡在說下資料庫的事務隔離級別一共四種如下:)
    
資料庫隔離級別:
        隔離級別                       是否存在髒讀  是否存在不可重複讀     是否存在幻讀;
    Read UnCommited(未提交讀)               Y            Y                     Y
    Read Commited (提交讀 oraclel預設)      N            Y                     Y
    Repeatable Read(不可重複讀(Msql預設))  N            N                     Y 
    Serializable(使用很少)                  N            N                     N
    


       Session.beginTrransaction().commit();

       事物提交後可以查詢到了。

Session.flush()語句但是為什麼不寫呢,因為commit()會預設呼叫flush();

hibernate中get方法和load方法的根本區別
如果你使用load方法,hibernate認為該id對應的物件(資料庫記錄)在資料庫中是一定存在的,所以它可以放心的使用,它可以放心的使用代理來延遲載入該物件。在用到物件中的其他屬性資料時才查詢資料庫,但是萬一資料庫中不存在該記錄,那沒辦法,只能拋異常ObjectNotFoundException,所說的load方法拋異常是指在使用該物件的資料時,資料庫中不存在該資料時拋異常,而不是在建立這個物件時。由於session中的快取對於hibernate來說是個相當廉價的資源,所以在load時會先查一下session快取看看該id對應的物件是否存在,不存在則建立代理。所以如果你知道該id在資料庫中一定有對應記錄存在就可以使用load方法來實現延遲載入。
對於get方法,hibernate會確認一下該id對應的資料是否存在,首先在session快取中查詢,然後在二級快取中查詢,還沒有就查資料庫,資料庫中沒有就返回null。

雖然好多書中都這麼說:“get()永遠只返回實體類”,但實際上這是不正確的,get方法如果在session快取中找到了該id對應的物件,如果剛好該物件前面是被代理過的,如被load方法使用過,或者被其他關聯物件延遲載入過,那麼返回的還是原先的代理物件,而不是實體類物件,如果該代理物件還沒有載入實體資料(就是id以外的其他屬性資料),那麼它會查詢二級快取或者資料庫來載入資料,但是返回的還是代理物件,只不過已經載入了實體資料。

前面已經講了,get方法首先查詢session快取,沒有的話查詢二級快取,最後查詢資料庫;反而load方法建立時首先查詢session快取,沒有就建立代理,實際使用資料時才查詢二級快取和資料庫。

總之對於get和load的根本區別,一句話,hibernate對於load方法認為該資料在資料庫中一定存在,可以放心的使用代理來延遲載入,如果在使用過程中發現了問題,就拋異常;而對於get方法,hibernate一定要獲取到真實的資料,否則返回null。

Hibernate生成的DAO類中函式功能說明(merge,saveOrUpdate,lock)

/**
      * 將傳入的detached狀態的物件的屬性複製到持久化物件中,並返回該持久化物件。
      * 如果該session中沒有關聯的持久化物件,載入一個。
      * 如果傳入物件未儲存,儲存一個副本並作為持久物件返回,傳入物件依然保持detached狀態。
      */

public Sysuser merge(Sysuser detachedInstance) {
      log.debug("merging Sysuser instance");
      try {
       Sysuser result = (Sysuser) getHibernateTemplate().merge(
         detachedInstance);
       log.debug("merge successful");
       return result;
      } catch (RuntimeException re) {
       log.error("merge failed", re);
       throw re;
      }
}

/**
      * 將傳入的物件持久化並儲存。 如果物件未儲存(Transient狀態),呼叫save方法儲存。
      * 如果物件已儲存(Detached狀態),呼叫update方法將物件與Session重新關聯。
      */
public void attachDirty(Sysuser instance) {
      log.debug("attaching dirty Sysuser instance");
      try {
       getHibernateTemplate().saveOrUpdate(instance);
       log.debug("attach successful");
      } catch (RuntimeException re) {
       log.error("attach failed", re);
       throw re;
      }
}

/**
      * 將傳入的物件狀態設定為Transient狀態
      */

public void attachClean(Sysuser instance) {
      log.debug("attaching clean Sysuser instance");
      try {
       getHibernateTemplate().lock(instance, LockMode.NONE);
       log.debug("attach successful");
      } catch (RuntimeException re) {
       log.error("attach failed", re);
       throw re;
      }
}