對(duì)于Hibernate這類ORM而言,緩存顯的尤為重要,它是持久層性能提升的關(guān)鍵.簡(jiǎn)單來講Hibernate就是對(duì)JDBC進(jìn)行封裝,以實(shí)現(xiàn)內(nèi)部狀態(tài)的管理,OR關(guān)系的映射等,但隨之帶來的就是數(shù)據(jù)訪問效率的降低,和性能的下降,而緩存就是彌補(bǔ)這一缺點(diǎn)的重要方法. 緩存就是數(shù)據(jù)庫數(shù)據(jù)在內(nèi)存中的臨時(shí)容器,包括數(shù)據(jù)庫數(shù)據(jù)在內(nèi)存中的臨時(shí)拷貝,它位于數(shù)據(jù)庫與數(shù)據(jù)庫訪問層中間.ORM在查詢數(shù)據(jù)時(shí)首先會(huì)根據(jù)自身的緩存管理策略,在緩存中查找相關(guān)數(shù)據(jù),如發(fā)現(xiàn)所需的數(shù)據(jù),則直接將此數(shù)據(jù)作為結(jié)果加以利用,從而避免了數(shù)據(jù)庫調(diào)用性能的開銷.而相對(duì)內(nèi)存操作而言,數(shù)據(jù)庫調(diào)用是一個(gè)代價(jià)高昂的過程. 一般來講ORM中的緩存分為以下幾類: 1.事務(wù)級(jí)緩存:即在當(dāng)前事務(wù)范圍內(nèi)的數(shù)據(jù)緩存.就Hibernate來講,事務(wù)級(jí)緩存是基于Session的生命周期實(shí)現(xiàn)的,每個(gè)Session內(nèi)部會(huì)存在一個(gè)數(shù)據(jù)緩存,它隨著Session的創(chuàng)建而存在,隨著Session的銷毀而滅亡,因此也稱為Session Level Cache. 2.應(yīng)用級(jí)緩存:即在某個(gè)應(yīng)用中或應(yīng)用中某個(gè)獨(dú)立數(shù)據(jù)庫訪問子集中的共享緩存,此緩存可由多個(gè)事務(wù)共享(數(shù)據(jù)庫事務(wù)或應(yīng)用事務(wù)),事務(wù)之間的緩存共享策略與應(yīng)用的事務(wù)隔離機(jī)制密切相關(guān).在Hibernate中,應(yīng)用級(jí)緩存由SessionFactory實(shí)現(xiàn),所有由一個(gè)SessionFactory創(chuàng)建的Session實(shí)例共享此緩存,因此也稱為SessionFactory Level Cache. 3.分布式緩存:即在多個(gè)應(yīng)用實(shí)例,多個(gè)JVM間共享的緩存策略.分布式緩存由多個(gè)應(yīng)用級(jí)緩存實(shí)例組成,通過某種遠(yuǎn)程機(jī)制(RMI,JMS)實(shí)現(xiàn)各個(gè)緩存實(shí)例間的數(shù)據(jù)同步,任何一個(gè)實(shí)例的數(shù)據(jù)修改,將導(dǎo)致整個(gè)集群間的數(shù)據(jù)狀態(tài)同步. Hibernate數(shù)據(jù)緩存: 1.內(nèi)部緩存(Session Level Cache也稱一級(jí)緩存): 舉例說明: java 代碼 public class Test { public void get(){ Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get("hibernate.TUser", 2); System.out.println(t.getName()); session.close(); } } 進(jìn)行測(cè)試:在控制臺(tái)打印出一條SQL語句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=? 說明進(jìn)行了一次數(shù)據(jù)庫的調(diào)用. 代碼更改如下: public class Test { public void get(){ Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get("hibernate.TUser", 2); System.out.println(t.getName()); TUser tt = (TUser)session.get("hibernate.TUser", 2); System.out.println(tt.getName()); session.close(); } } 再進(jìn)行測(cè)試:進(jìn)行了兩次查詢,控制臺(tái)仍然只打出一條SQL語句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=? 說明還是只進(jìn)行了一次數(shù)據(jù)庫的調(diào)用. 再將代碼更改如下: public class Test { public void get(){ Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get("hibernate.TUser", 2); System.out.println(t.getName()); session.close(); Session session1 = HibernateSessionFactory.getSession(); TUser tt = (TUser)session1.get("hibernate.TUser", 2); System.out.println(tt.getName()); session1.close(); } } 繼續(xù)測(cè)試:進(jìn)行兩次查詢控制臺(tái)打印兩條SQL語句:Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=? Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.sex as sex0_0_ from test.t_user tuser0_ where tuser0_.id=? 結(jié)論:Hibernate進(jìn)行查詢時(shí)總是先在緩存中進(jìn)行查詢,如緩存中沒有所需數(shù)據(jù)才進(jìn)行數(shù)據(jù)庫的查詢.Hibernate的內(nèi)部緩存是基于Session的生命周期的,也就是說存在于每個(gè)Session內(nèi)部,它隨著Session的創(chuàng)建而存在,隨著Session的銷毀而滅亡,內(nèi)部緩存一般由Hibernate自動(dòng)維護(hù),不需要人為干預(yù),當(dāng)然我們也可以根據(jù)需要進(jìn)行相應(yīng)操作:Session.evict(Object)(將指定對(duì)象從內(nèi)部緩存清除),Session.clear()(清空內(nèi)部緩存).(如在兩次查詢間加入Session.clear()將會(huì)清空內(nèi)部緩存,使得一個(gè)Sesion內(nèi)部的兩次相同的查詢要對(duì)數(shù)據(jù)庫進(jìn)行兩次操作). 2.二級(jí)緩存:(有時(shí)稱為SessionFactory Level Cache) Hibernate本身并未提供二級(jí)緩存的產(chǎn)品化實(shí)現(xiàn)(只提供了一個(gè)基于HashTable的簡(jiǎn)單緩存以供調(diào)試),這里我使用的是第三方緩存組件:EHcache.Hibernate的二級(jí)緩存實(shí)現(xiàn)需要進(jìn)行以下配置(Hibernate3): 首先在hibernate.cfg.xml內(nèi)添加: <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> <property name="hibernate.cache.use_query_cache">true</property> 然后在映射文件中添加: <cache usage="read-only"/> 測(cè)試上面代碼:控制臺(tái)輸出多了這樣一句[ WARN] (CacheFactory.java:43) - read-only cache configured for mutable class: hibernate.TUser,二級(jí)緩存啟用成功!! java 代碼 public class Test { public void executeQuery(){ List list = new ArrayList(); Session session = HibernateSessionFactory.getSession(); Query query = session.createQuery("from TUser t"); query.setCacheable(true);//激活查詢緩存 list = query.list(); session.close(); } public void get(){ Session session = HibernateSessionFactory.getSession(); TUser t = (TUser)session.get("hibernate.TUser", 2); System.out.println(t.getName()); session.close(); } } 測(cè)試:控制臺(tái)只輸出一條SQL語句:Hibernate: select tuser0_.id as id0_, tuser0_.name as name0_, tuser0_.sex as sex0_ from test.t_user tuser0_(即Query query = session.createQuery("from TUser t")這句代碼所對(duì)應(yīng)的SQL). executeQuery()方法與get()方法使用的是不同的Session!!可是executeQuery()方法與get()方法只對(duì)數(shù)據(jù)庫進(jìn)行了一次操作,這就是二級(jí)緩存在起作用了. 結(jié)論:Hibernate二級(jí)緩存是SessionFactory級(jí)的緩存,它允許多個(gè)Session間共享,使用時(shí)需要使用第三方的緩存組件,新版Hibernate將EHcache作為默認(rèn)的二級(jí)緩存實(shí)現(xiàn). 緩存同步策略:緩存同步策略決定了數(shù)據(jù)對(duì)象在緩存中的存取規(guī)則,我們必須為每個(gè)實(shí)體類指定相應(yīng)的緩存同步策略.Hibernate中提供了4種不同的緩存同步策略:(暫時(shí)只記個(gè)概念吧) 1.read-only:只讀.對(duì)于不會(huì)發(fā)生改變的數(shù)據(jù)可使用. 2.nonstrict-read-write:如果程序?qū)Σl(fā)訪問下的數(shù)據(jù)同步要求不嚴(yán)格,且數(shù)據(jù)更新頻率較低,采用本緩存同步策略可獲得較好性能. 3.read-write:嚴(yán)格的讀寫緩存.基于時(shí)間戳判定機(jī)制,實(shí)現(xiàn)了"read committed"事務(wù)隔離等級(jí).用于對(duì)數(shù)據(jù)同步要求的情況,但不支持分布式緩存,實(shí)際應(yīng)用中使用最多的緩存同步策略. 4.transactional:事務(wù)型緩存,必須運(yùn)行在JTA事務(wù)環(huán)境中.此緩存中,緩存的相關(guān)操作被添加到事務(wù)中(此緩存類似于一個(gè)內(nèi)存數(shù)據(jù)庫),如事務(wù)失敗,則緩沖池的數(shù)據(jù)會(huì)一同回滾到事務(wù)的開始之前的狀態(tài).事務(wù)型緩存實(shí)現(xiàn)了"Repeatable read"事務(wù)隔離等級(jí),有效保證了數(shù)據(jù)的合法性,適應(yīng)于對(duì)關(guān)鍵數(shù)據(jù)的緩存,Hibernate內(nèi)置緩存中,只有JBossCache支持事務(wù)型緩存. |
聯(lián)系客服