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 級別的快取,它同
2.兩個session 不能共享一級快取,因它會伴隨session的生命週期的建立和消毀;
3.Session快取是實體級別的快取,就是隻有在查詢物件級別的時候才使用,如果
使用HQL和SQL是查詢屬性級別的,是不使用一級快取的!切記!!!!
4 . iterate 查詢使用快取,會發出查詢Id的SQL和HQL語句,但不會發出查實體的,
它查詢完會把相應的實體放到快取裡邊,一些實體查詢如果快取裡邊有,就從快取中查詢,但還是會發出查詢id的SQL和HQL語句。如果快取中沒有它會資料庫中查詢,然後將查詢到的實體一個一個放到快取中去,所以會有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;
}
}