Hibernate一級(jí)緩存和二級(jí)緩存詳解
一、一級(jí)緩存二級(jí)緩存的概念解釋
(1)一級(jí)緩存就是Session級(jí)別的緩存,一個(gè)Session做了一個(gè)查詢操作,它會(huì)把這個(gè)操作的結(jié)果放在一級(jí)緩存中,如果短時(shí)間內(nèi)這個(gè)session(一定要同一個(gè)session)又做了同一個(gè)操作,那么hibernate直接從一級(jí)緩存中拿,而不會(huì)再去連數(shù)據(jù)庫,取數(shù)據(jù);
(2)二級(jí)緩存就是SessionFactory級(jí)別的緩存,顧名思義,就是查詢的時(shí)候會(huì)把查詢結(jié)果緩存到二級(jí)緩存中,如果同一個(gè)sessionFactory創(chuàng)建的某個(gè)session執(zhí)行了相同的操作,hibernate就會(huì)從二級(jí)緩存中拿結(jié)果,而不會(huì)再去連接數(shù)據(jù)庫;
(3)Hibernate中提供了兩級(jí)Cache,第一級(jí)別的緩存是Session級(jí)別的緩存,它是屬于事務(wù)范圍的緩存。這一級(jí)別的緩存由hibernate管理的,一般情況下無需進(jìn)行干預(yù);第二級(jí)別的緩存是SessionFactory級(jí)別的緩存,它是屬于進(jìn)程范圍或群集范圍的緩存。這一級(jí)別的緩存可以進(jìn)行配置和更改,并且可以動(dòng)態(tài)加載和卸載。 Hibernate還為查詢結(jié)果提供了一個(gè)查詢緩存,它依賴于第二級(jí)緩存;
二、一級(jí)緩存和二級(jí)緩存的比較
(1)第一級(jí)緩存 第二級(jí)緩存 存放數(shù)據(jù)的形式相互關(guān)聯(lián)的持久化對(duì)象 對(duì)象的散裝數(shù)據(jù) 緩存的范圍事務(wù)范圍,每個(gè)事務(wù)都有單獨(dú)的第一級(jí)緩存進(jìn)程范圍或集群范圍,緩存被同一個(gè)進(jìn)程或集群范圍內(nèi)的所有事務(wù)共享并發(fā)訪問策略由于每個(gè)事務(wù)都擁有單獨(dú)的第一級(jí)緩存,不會(huì)出現(xiàn)并發(fā)問題,無需提供并發(fā)訪問策略由于多個(gè)事務(wù)會(huì)同時(shí)訪問第二級(jí)緩存中相同數(shù)據(jù),因此必須提供適當(dāng)?shù)牟l(fā)訪問策略,來保證特定的事務(wù)隔離級(jí)別數(shù)據(jù)過期策略沒有提供數(shù)據(jù)過期策略。
(2)處于一級(jí)緩存中的對(duì)象永遠(yuǎn)不會(huì)過期,除非應(yīng)用程序顯式清空緩存或者清除特定的對(duì)象必須提供數(shù)據(jù)過期策略,如基于內(nèi)存的緩存中的對(duì)象的最大數(shù)目,允許對(duì)象處于緩存中的最長時(shí)間,以及允許對(duì)象處于緩存中的最長空閑時(shí)間物理存儲(chǔ)介質(zhì)內(nèi)存內(nèi)存和硬盤。
(3)對(duì)象的散裝數(shù)據(jù)首先存放在基于內(nèi)存的緩存中,當(dāng)內(nèi)存中對(duì)象的數(shù)目達(dá)到數(shù)據(jù)過期策略中指定上限時(shí),就會(huì)把其余的對(duì)象寫入基于硬盤的緩存中。
(4)緩存的軟件實(shí)現(xiàn)在Hibernate的Session的實(shí)現(xiàn)中包含了緩存的實(shí)現(xiàn)由第三方提供,Hibernate僅提供了緩存適配器(CacheProvider)。用于把特定的緩存插件集成到Hibernate中。
(5)啟用緩存的方式只要應(yīng)用程序通過Session接口來執(zhí)行保存、更新、刪除、加載和查詢數(shù)據(jù)庫數(shù)據(jù)的操作,Hibernate就會(huì)啟用第一級(jí)緩存,把數(shù)據(jù)庫中的數(shù)據(jù)以對(duì)象的形式拷貝到緩存中,對(duì)于批量更新和批量刪除操作,如果不希望啟用第一級(jí)緩存,可以繞過Hibernate API,直接通過JDBC API來執(zhí)行指操作。
(6)用戶可以在單個(gè)類或類的單個(gè)集合的粒度上配置第二級(jí)緩存。如果類的實(shí)例被經(jīng)常讀但很少被修改,就可以考慮使用第二級(jí)緩存。
(7)只有為某個(gè)類或集合配置了第二級(jí)緩存,Hibernate在運(yùn)行時(shí)才會(huì)把它的實(shí)例加入到第二級(jí)緩存中。用戶管理緩存的方式第一級(jí)緩存的物理介質(zhì)為內(nèi)存,由于內(nèi)存容量有限,必須通過恰當(dāng)?shù)臋z索策略和檢索方式來限制加載對(duì)象的數(shù)目。Session的 evit()方法可以顯式清空緩存中特定對(duì)象,但這種方法不值得推薦。第二級(jí)緩存的物理介質(zhì)可以是內(nèi)存和硬盤,因此第二級(jí)緩存可以存放大量的數(shù)據(jù),數(shù)據(jù)過期策略的maxElementsInMemory屬性值可以控制內(nèi)存中的對(duì)象數(shù)目。
(8)管理第二級(jí)緩存主要包括兩個(gè)方面:選擇需要使用第二級(jí)緩存的持久類,設(shè)置合適的并發(fā)訪問策略:選擇緩存適配器,設(shè)置合適的數(shù)據(jù)過期策略。
三、 一級(jí)緩存的管理
(1)當(dāng)應(yīng)用程序調(diào)用Session的save()、update()、savaeOrUpdate()、get()或load(),以及調(diào)用查詢接口的 list()、iterate()或filter()方法時(shí),如果在Session緩存中還不存在相應(yīng)的對(duì)象,Hibernate就會(huì)把該對(duì)象加入到第一級(jí)緩存中。當(dāng)清理緩存時(shí),Hibernate會(huì)根據(jù)緩存中對(duì)象的狀態(tài)變化來同步更新數(shù)據(jù)庫。 Session為應(yīng)用程序提供了兩個(gè)管理緩存的方法: evict(Object obj):從緩存中清除參數(shù)指定的持久化對(duì)象。 clear():清空緩存中所有持久化對(duì)象。
(2)save、update、saveOrupdate、load、list、iterate、lock會(huì)向一級(jí)緩存存放數(shù)據(jù);
save 案例:
//添加一個(gè)學(xué)生 Student student=new Student(); student.setName("小東"); s.save(student);//放入一級(jí)緩存 //我馬上查詢 Student stu2=(Student) s.get(Student.class, student.getId()); //select System.out.println("你剛剛加入的學(xué)生名字是"+stu2.getName());
(3)什么操作會(huì)從一級(jí)緩存取數(shù)據(jù):get、load、list
get / load 會(huì)首先從一級(jí)緩存中取,如沒有.再有不同的操作[get 會(huì)立即向數(shù)據(jù)庫發(fā)請(qǐng)求,而load 會(huì)返回一個(gè)代理對(duì)象,直到用戶真的去使用數(shù)據(jù),才會(huì)向數(shù)據(jù)庫發(fā)請(qǐng)求;
//查詢45號(hào)學(xué)生 Student stu=(Student) s.get(Student.class, 45); System.out.println("|||||||||||||||||||"); String hql="from Student where id=45"; Student stu2=(Student) s.createQuery(hql).uniqueResult(); System.out.println(stu2.getName());
從上面的案例,我們看出 query.list() query.uniueResut() 不會(huì)從一級(jí)緩取數(shù)據(jù)! 但是query.list 或者query.uniqueRestu() 會(huì)向一級(jí)緩存放數(shù)據(jù)的.
注意:
① 一級(jí)緩存不需要配置,就可以使用,它本身沒有保護(hù)機(jī)制,所以我們程序員要考慮這個(gè)問題,我們可以同 evict 或者 clear來清除session緩存中對(duì)象. evict 是清除一個(gè)對(duì)象,clear是清除所有的sesion緩存對(duì)象
② session級(jí)緩存中對(duì)象的生命周期, 當(dāng)session關(guān)閉后,就自動(dòng)銷毀.
③ 我們自己用HashMap來模擬一個(gè)Session緩存,加深對(duì)緩存的深入.
四、Hibernate二級(jí)緩存的管理
1. Hibernate二級(jí)緩存策略的一般過程如下:
1) 條件查詢的時(shí)候,總是發(fā)出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數(shù)據(jù)庫,一次獲得所有的數(shù)據(jù)對(duì)象。
2) 把獲得的所有數(shù)據(jù)對(duì)象根據(jù)ID放入到第二級(jí)緩存中。
3) 當(dāng)Hibernate根據(jù)ID訪問數(shù)據(jù)對(duì)象的時(shí)候,首先從Session一級(jí)緩存中查;查不到,如果配置了二級(jí)緩存,那么從二級(jí)緩存中查;查不到,再查詢數(shù)據(jù)庫,把結(jié)果按照ID放入到緩存。
4) 刪除、更新、增加數(shù)據(jù)的時(shí)候,同時(shí)更新緩存。Hibernate二級(jí)緩存策略,是針對(duì)于ID查詢的緩存策略,對(duì)于條件查詢則毫無作用。為此,Hibernate提供了針對(duì)條件查詢的Query Cache。
5) 二級(jí)緩存的對(duì)象可能放在內(nèi)存,也可能放在磁盤.
2. 什么樣的數(shù)據(jù)適合存放到第二級(jí)緩存中?
1) 很少被修改的數(shù)據(jù)
2) 不是很重要的數(shù)據(jù),允許出現(xiàn)偶爾并發(fā)的數(shù)據(jù)
3) 不會(huì)被并發(fā)訪問的數(shù)據(jù)
4) 參考數(shù)據(jù),指的是供應(yīng)用參考的常量數(shù)據(jù),它的實(shí)例數(shù)目有限,它的實(shí)例會(huì)被許多其他類的實(shí)例引用,實(shí)例極少或者從來不會(huì)被修改。
3. 不適合存放到第二級(jí)緩存的數(shù)據(jù)?
1) 經(jīng)常被修改的數(shù)據(jù)
2) 財(cái)務(wù)數(shù)據(jù),絕對(duì)不允許出現(xiàn)并發(fā)
3) 與其他應(yīng)用共享的數(shù)據(jù)。
4. 常用的緩存插件 Hibernater二級(jí)緩存是一個(gè)插件,下面是幾種常用的緩存插件:
◆EhCache:可作為進(jìn)程范圍的緩存,存放數(shù)據(jù)的物理介質(zhì)可以是內(nèi)存或硬盤,對(duì)Hibernate的查詢緩存提供了支持。
◆OSCache:可作為進(jìn)程范圍的緩存,存放數(shù)據(jù)的物理介質(zhì)可以是內(nèi)存或硬盤,提供了豐富的緩存數(shù)據(jù)過期策略,對(duì)Hibernate的查詢緩存提供了支持。
◆SwarmCache:可作為群集范圍內(nèi)的緩存,但不支持Hibernate的查詢緩存。
◆JBossCache:可作為群集范圍內(nèi)的緩存,支持事務(wù)型并發(fā)訪問策略,對(duì)Hibernate的查詢緩存提供了支持。
5. 配置Hibernate二級(jí)緩存的主要步驟:
1) 選擇需要使用二級(jí)緩存的持久化類,設(shè)置它的命名緩存的并發(fā)訪問策略。這是最值得認(rèn)真考慮的步驟。
2) 選擇合適的緩存插件,然后編輯該插件的配置文件。
<property name="hbm2ddl.auto">update</property> <!-- 啟動(dòng)二級(jí)緩存 --> <property name="cache.use_second_level_cache">true</property> <!-- 指定使用哪種二級(jí)緩存 --> <property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property> <mapping resource="com/hsp/domain/Department.hbm.xml" /> <mapping resource="com/hsp/domain/Student.hbm.xml" /> <!-- 指定哪個(gè)domain啟用二級(jí)緩存 特別說明二級(jí)緩存策略: 1. read-only 2. read-write 3. nonstrict-read-write 4. transcational --> <class-cache class="com.hsp.domain.Student" usage="read-write"/>
3)可以把oscache.properties文件放在 src目錄下,這樣你可以指定放入二級(jí)緩存的對(duì)象capacity 大小. 默認(rèn)1000
6.使用二級(jí)緩存:
// TODO Auto-generated method stub //通過獲取一個(gè)sesion,讓hibernate框架運(yùn)行(config->加載hibernate.cfg.xml) Session s=null; Transaction tx=null; try { //我們使用基礎(chǔ)模板來講解. s=HibernateUtil.openSession(); tx=s.beginTransaction(); //查詢45號(hào)學(xué)生 Student stu1=(Student) s.get(Student.class, 45);//45->一級(jí)緩存 System.out.println(stu1.getName()); tx.commit(); } catch (Exception e) { e.printStackTrace(); if(tx!=null){ tx.rollback(); } }finally{ if(s!=null && s.isOpen()){ s.close(); } } System.out.println("*********************************"); try { //我們使用基礎(chǔ)模板來講解. s=HibernateUtil.openSession(); tx=s.beginTransaction(); //查詢45號(hào)學(xué)生 Student stu1=(Student) s.get(Student.class, 45); System.out.println(stu1.getName()); Student stu3=(Student) s.get(Student.class, 46); System.out.println(stu3.getName()); tx.commit(); } catch (Exception e) { e.printStackTrace(); if(tx!=null){ tx.rollback(); } }finally{ if(s!=null && s.isOpen()){ s.close(); } } //完成一個(gè)統(tǒng)計(jì),統(tǒng)計(jì)的信息在Sessfactory //SessionFactory對(duì)象. Statistics statistics= HibernateUtil.getSessionFactory().getStatistics(); System.out.println(statistics); System.out.println("放入"+statistics.getSecondLevelCachePutCount()); System.out.println("命中"+statistics.getSecondLevelCacheHitCount()); System.out.println("錯(cuò)過"+statistics.getSecondLevelCacheMissCount());
在配置了二級(jí)緩存后,請(qǐng)大家要注意可以通過 Statistics,查看你的配置命中率高不高
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
- Hibernate核心類和接口的詳細(xì)介紹
- Hibernate的各種保存方式的區(qū)別詳解
- Hibernate中Session.get()方法和load()方法的詳細(xì)比較
- Hibernate用ThreadLocal模式(線程局部變量模式)管理Session
- hibernate測(cè)試時(shí)遇到的幾個(gè)異常及解決方法匯總
- Hibernate中使用HQLQuery查詢?nèi)繑?shù)據(jù)和部分?jǐn)?shù)據(jù)的方法實(shí)例
- Hibernate實(shí)現(xiàn)many-to-many的映射關(guān)系
- SpringBoot 使用hibernate validator校驗(yàn)
- Hibernate之CRUD操作實(shí)踐
- Hibernate連接三種數(shù)據(jù)庫的配置文件
相關(guān)文章
深入理解SpringMVC中央調(diào)度器DispatcherServlet
這篇文章主要介紹了SpringMVC核心之中央調(diào)度器DispatcherServlet的相關(guān)知識(shí),包括SpringMVC請(qǐng)求處理過程及SrpingMVC容器和spring?IOC容器關(guān)系,需要的朋友可以參考下2022-05-05解決SpringBoot項(xiàng)目啟動(dòng)成功但接口訪問404的問題
這篇文章主要介紹了如何解決SpringBoot項(xiàng)目啟動(dòng)成功但接口訪問404的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,接下來就跟著小編一起來看看吧2023-07-07Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(40)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07Spring中的之啟動(dòng)過程obtainFreshBeanFactory詳解
這篇文章主要介紹了Spring中的之啟動(dòng)過程obtainFreshBeanFactory詳解,在refresh時(shí),prepareRefresh后,馬上就調(diào)用了obtainFreshBeanFactory創(chuàng)建beanFactory以及掃描bean信息(beanDefinition),并通過BeanDefinitionRegistry注冊(cè)到容器中,需要的朋友可以參考下2024-02-02詳解springboot中各個(gè)版本的redis配置問題
這篇文章主要介紹了詳解springboot中各個(gè)版本的redis配置問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04JAVA對(duì)象JSON數(shù)據(jù)互相轉(zhuǎn)換的四種常見情況
這篇文章主要介紹了JAVA對(duì)象JSON數(shù)據(jù)互相轉(zhuǎn)換的四種常見情況,需要的朋友可以參考下2014-04-04Java從單體架構(gòu)升級(jí)到微服務(wù)要注意的一些問題
這篇文章主要介紹了Java從單體架構(gòu)升級(jí)到微服務(wù)要注意的一些問題,對(duì)架構(gòu)感興趣的同學(xué),可以參考下2021-04-04System.getProperty(“l(fā)ine.separator“)含義及意義詳解
這篇文章主要介紹了System.getProperty(“l(fā)ine.separator“)含義,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05