欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis查詢緩存實(shí)例詳解

 更新時(shí)間:2017年06月16日 14:17:46   投稿:mrr  
查詢緩存的使用,主要是為了提高查詢?cè)L問速度。這篇文章主要介紹了MyBatis查詢緩存,需要的朋友可以參考下

查詢緩存的使用,主要是為了提高查詢?cè)L問速度。將用戶對(duì)同一數(shù)據(jù)的重復(fù)查詢過程簡(jiǎn)化,不再每次均從數(shù)據(jù)庫(kù)查詢獲取結(jié)果數(shù)據(jù),從而提高訪問速度。

MyBatis的查詢緩存機(jī)制,根據(jù)緩存區(qū)的作用域(生命周期)可劃分為兩種:一級(jí)緩存與二級(jí)緩存

一、一級(jí)查詢緩存

MyBatis一級(jí)緩存是基于org.apache.ibatis.cache.impl.PerpetualCache類的HashMap本地緩存,其作用域是Sqlsession。在同一個(gè)Sqlsession中兩次執(zhí)行相同的sql語(yǔ)句,第一次執(zhí)行完畢后,會(huì)將查詢結(jié)果寫入到緩存中,第二次會(huì)從緩存中直接獲取數(shù)據(jù),而不再到數(shù)據(jù)庫(kù)中進(jìn)行查詢,從而提高查詢效率。

當(dāng)一個(gè)Sqlsession結(jié)束后,該Sqlsession中的一級(jí)緩存也就不存在了。MyBatis默認(rèn)一級(jí)緩存是開啟狀態(tài),且不能關(guān)閉。

1.一級(jí)緩存的存在性證明

測(cè)試類:

//證明一級(jí)緩存的存在
@Test
public void test01(){
 //第一次查詢
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 //第二次查詢
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}

mapper:

<mapper namespace="com.hcx.dao.IStudentDao">  
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
</mapper>

控制臺(tái):

執(zhí)行完后,發(fā)現(xiàn)只執(zhí)行了一次從DB中的查詢,第二次的結(jié)果是直接輸出的。說明,第二次是從Sqlsession緩存中讀取的。

2.從緩存讀取數(shù)據(jù)的依據(jù)是sql的id

一級(jí)緩存緩存的是相同sql映射id的查詢結(jié)果,而非相同sql語(yǔ)句的查詢結(jié)果。因?yàn)镸yBatis內(nèi)部對(duì)于查詢緩存,無論是一級(jí)查詢還是二級(jí)查詢,其底層均使用一個(gè)hashmap實(shí)現(xiàn):key為sql的id相關(guān)內(nèi)容,value為從數(shù)據(jù)庫(kù)中查詢出的結(jié)果。

mapper:

<mapper namespace="com.hcx.dao.IStudentDao">
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
  <select id="selectStudnetById2" resultType="com.hcx.beans.Student">
   select id,name,age,score,birthday from student where id=#{id}
  </select>
</mapper>

dao接口:

public interface IStudentDao {  
 Student selectStudentById(int id);
 Student selectStudentById2(int id); 
}

測(cè)試類:

//證明從一級(jí)緩存中讀取數(shù)據(jù)的依據(jù):
//MyBatis:sql的id+sql語(yǔ)句
//hibernate:查詢結(jié)果對(duì)象的id
@Test
public void test02(){
 Student student = dao.selectStudentById(2);
 System.out.println(student);

 Student student2 = dao.selectStudentById2(2);
 System.out.println(student2);  
}

控制臺(tái):

查看控制臺(tái),發(fā)現(xiàn)第二次查詢結(jié)果與第一次的完全相同,但第二次查詢并沒有從緩存中讀取數(shù)據(jù),而是直接從DB中進(jìn)行的查詢。這是因?yàn)閺木彺孀x取數(shù)據(jù)的依據(jù)是查詢sql的映射id,而非查詢結(jié)果。

3.增刪改對(duì)一級(jí)查詢緩存的影響

增刪改操作,無論是否進(jìn)行提交Sqlsession.commit(),均會(huì)清空一級(jí)查詢緩存,使查詢?cè)俅螐腄B中select。

測(cè)試類:

@Test
public void test03(){
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 //增刪改操作都會(huì)清空一級(jí)緩存,無論是否提交
 dao.insertStudent(new Student("趙六",26,96.6));
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}

控制臺(tái):


二、內(nèi)置二級(jí)查詢緩存

MyBatis查詢緩存的作用域是根據(jù)映射文件mapper的namespace劃分的,相同namespace的mapper查詢數(shù)據(jù)存放在同一個(gè)緩存區(qū)域。不同namespace下的數(shù)據(jù)互不干擾。

無論是一級(jí)緩存還是二級(jí)緩存,都是按照namespace進(jìn)行分別存放的。但一、二級(jí)緩存的不同之處在于,Sqlsession一旦關(guān)閉,則Sqlsession中的數(shù)據(jù)將不存在,即一級(jí)緩存就不復(fù)存在。而二級(jí)緩存的生命周期會(huì)與整個(gè)應(yīng)用同步,與Sqlsession是否關(guān)閉無關(guān)。

使用二級(jí)緩存的目的,不是共享數(shù)據(jù),因?yàn)镸yBatis從緩存中讀取數(shù)據(jù)的依據(jù)是sql的id,而非查詢出的對(duì)象。所以,二級(jí)緩存中的數(shù)據(jù)不是為了在多個(gè)查詢之間共享(所有查詢中只要查詢結(jié)果中存在該對(duì)象的,就直接從緩存中讀取,這是對(duì)數(shù)據(jù)的共享,hibernate中的緩存就是為了共享,但MyBatis不是),而是為了延長(zhǎng)該查詢結(jié)果的保存時(shí)間,提高系統(tǒng)性能。

1.二級(jí)緩存用法

二級(jí)緩存的使用只需要完成兩步:

序列化實(shí)體

在mapper映射文件中添加<cache/>標(biāo)簽

1.實(shí)體序列化

要求查詢結(jié)果所涉及到的實(shí)體類要實(shí)現(xiàn)java.io.Serializable接口。若該實(shí)體類存在父類,或其具有域?qū)傩裕瑒t父類與域?qū)傩灶愐惨獙?shí)現(xiàn)序列化接口。

public class Student implements Serializable{
 private Integer id;
 private String name;
 private int age;
 private double score;
}

2.mapper映射文件中添加<cache/>標(biāo)簽

在mapper映射文件中的<mapper/>標(biāo)簽中添加<cache/>子標(biāo)簽

<mapper namespace="com.hcx.dao.IStudentDao">
 <cache/>
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
</mapper>

3.二級(jí)緩存的配置

為<cache/>標(biāo)簽添加一些相關(guān)屬性設(shè)置,可以對(duì)二級(jí)緩存的運(yùn)行性能進(jìn)行控制。若不指定設(shè)置,則均保持默認(rèn)值。

<cache eviction="IFIO" flushInterval="10800000"
  readOnly="true" size="512"/>

eviction:逐出策略。當(dāng)二級(jí)緩存中的對(duì)象達(dá)到最大值時(shí),就需要通過逐出策略將緩存中的對(duì)象移出緩存。默認(rèn)為L(zhǎng)RU。常用的策略有FIFO和LRU

flushInterval:刷新緩存的時(shí)間間隔,單位毫秒。這里的刷新緩存即清空緩存。一般不指定,即當(dāng)執(zhí)行增刪改時(shí)刷新緩存。

readOnly:設(shè)置緩存中數(shù)據(jù)是否只讀。只讀的緩存會(huì)給所有調(diào)用者返回緩存對(duì)象的相同實(shí)例,因此這些對(duì)象不能被修改,這提供了很重要的性能優(yōu)勢(shì)。但讀寫的緩存會(huì)返回緩存對(duì)象的拷貝。這會(huì)慢一些,但是安全,因此默認(rèn)是false。
size:二級(jí)緩存中可以存放的最多對(duì)象個(gè)數(shù)。默認(rèn)為1024個(gè)。

2.二級(jí)緩存的存在性證明

對(duì)于映射文件中的同一個(gè)查詢,肯定是同一個(gè)namespace中的查詢。在一次查詢后,將Sqlsession關(guān)閉,再進(jìn)行一次相同查詢,發(fā)現(xiàn)并沒有到DB中進(jìn)行select查詢,說明二級(jí)緩存是存在的。

//證明二級(jí)緩存的存在
@Test
public void test01(){
 //第一次查詢
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 sqlSession.close();
 sqlSession = MyBatisUtils.getSqlSession();
 dao = sqlSession.getMapper(IStudentDao.class);
 //第二次查詢
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}

查看控制臺(tái):

Cache Hit Ratio表示緩存命中率。開啟二級(jí)緩存后,每執(zhí)行一次查詢,系統(tǒng)都會(huì)計(jì)算一次二級(jí)緩存的命中率。第一次查詢也是先從緩存中查詢,只不過緩存中一定是沒有的。所以會(huì)再?gòu)腄B中查詢。由于二級(jí)緩存中不存在該數(shù)據(jù),所以命中率為0.但第二次查詢是從二級(jí)緩存中讀取的,所以這一次的命中率為1/2=0.5。當(dāng)然,若有第三次查詢,則命中率為1/3=0.66

3.增刪改對(duì)二級(jí)緩存的影響

增刪改操作,無論是否進(jìn)行提交sqlSession.commit(),均會(huì)清空一級(jí)、二級(jí)緩存,使查詢?cè)俅螐腄B中select。

測(cè)試類:

@Testpublic void test02(){
 //第一次查詢
 Student student = dao.selectStudentById(2);
 System.out.println(student);
 sqlSession.close();
 sqlSession = MyBatisUtils.getSqlSession();
 dao = sqlSession.getMapper(IStudentDao.class);
 //插入
 dao.insertStudent(new Student("",0,0));
 //第二次查詢
 Student student2 = dao.selectStudentById(2);
 System.out.println(student2);  
}

控制臺(tái):

注意,在第二次查詢時(shí)的緩存命中率為0.5,但還是從DB中查詢了。說明在緩存中與該查詢相對(duì)應(yīng)的key是存在的,但其value被清空。而value被清空的原因是前面執(zhí)行了對(duì)DB的增刪改操作,所以不會(huì)從緩存中直接將null值返回,而是從DB中進(jìn)行查詢。

說明:

二級(jí)緩存的清空,實(shí)質(zhì)上是對(duì)所查找key對(duì)應(yīng)的value置為null,而非將<key,value>對(duì),即entry對(duì)象刪除。

從DB中進(jìn)行select查詢的條件是:緩存中根本不存在這個(gè)key或者緩存中存在該key所對(duì)應(yīng)的entry對(duì)象,但value為null。

設(shè)置增刪改操作不刷新二級(jí)緩存:

若要使某個(gè)增、刪或改操作不清空二級(jí)緩存,則需要在其<insert/>或<delete/>或<update/>中添加屬性flushCache="false",默認(rèn)為true。

<insert id="insertStudent" flushCache="false">
  insert into student(name,age,score) values(#{name},#{age},#{score})
 </insert>

4.二級(jí)緩存的關(guān)閉

二級(jí)緩存默認(rèn)為開啟狀態(tài)。若要將其關(guān)閉,則需要進(jìn)行相關(guān)設(shè)置。
根據(jù)關(guān)閉的范圍大小,可以分為全局關(guān)閉和局部關(guān)閉

1.全局關(guān)閉(在配置文件中設(shè)置)

全局關(guān)閉是指整個(gè)應(yīng)用的二級(jí)緩存全部關(guān)閉,所有查詢均不使用二級(jí)緩存。全局開關(guān)設(shè)置在主配置文件的全局設(shè)置<settings/>中,該屬性為cacheEnabled,設(shè)置為false,則關(guān)閉;設(shè)置為true,則開啟,默認(rèn)值為true。即二級(jí)緩存默認(rèn)是開啟的。

<!-- 關(guān)閉二級(jí)緩存 -->
<settings>
 <setting name="cacheEnabled" value="false"/>
</settings>

2.局部關(guān)閉(在映射文件的每個(gè)select中設(shè)置)

局部關(guān)閉指整個(gè)應(yīng)用的二級(jí)緩存是開啟的,但只是針對(duì)某個(gè)<select/>查詢,不使用二級(jí)緩存。此時(shí)可以單獨(dú)只關(guān)閉該<select/>標(biāo)簽的二級(jí)緩存。

在該要關(guān)閉二級(jí)緩存的<select/>標(biāo)簽中,將其屬性u(píng)seCache設(shè)置為false,即可關(guān)閉該查詢的二級(jí)緩存。該屬性默認(rèn)為true,即每個(gè)<select/>查詢的二級(jí)緩存默認(rèn)是開啟的。

<!--useCache="false"對(duì)當(dāng)前sql的二級(jí)緩存的局部關(guān)閉 -->
 <select id=selectStudentById useCache="false" resultType="com.hcx.beans.Student">
  select * from student where id=#{id}
 </select>

5.二級(jí)緩存的使用原則

1.只能在一個(gè)命名空間下使用二級(jí)緩存

由于二級(jí)緩存中的數(shù)據(jù)是基于namespace的,即不同namespace中的數(shù)據(jù)互不干擾。在多個(gè)namespace中若均存在對(duì)同一個(gè)表的操作,那么這多個(gè)namespace中的數(shù)據(jù)可能就會(huì)出現(xiàn)不一致現(xiàn)象。

2.在單表上使用二級(jí)緩存

如果一個(gè)表與其它表有關(guān)聯(lián)關(guān)系,那么久非常有可能存在多個(gè)namespace對(duì)同一數(shù)據(jù)的操作。而不同namespace中的數(shù)據(jù)互補(bǔ)干擾,所以就有可能出現(xiàn)多個(gè)namespace中的數(shù)據(jù)不一致現(xiàn)象。

3.查詢多于修改時(shí)使用二級(jí)緩存

在查詢操作遠(yuǎn)遠(yuǎn)多于增刪改操作的情況下可以使用二級(jí)緩存。因?yàn)槿魏卧鰟h改操作都將刷新二級(jí)緩存,對(duì)二級(jí)緩存的頻繁刷新將降低系統(tǒng)性能。

三、ehcache二級(jí)查詢緩存

MyBatis允許使用第三方緩存產(chǎn)品。ehCache就是其中一種。

注意:使用ehcache二級(jí)緩存,實(shí)體類無需實(shí)現(xiàn)序列化接口。

1.導(dǎo)入jar包

2.添加ehcache.xml

解壓ehcache的核心jar包ehcache-core-2.6.8.jar,將其中的一個(gè)配置文件ehcache-failsafe.xml直接放到項(xiàng)目的src目錄下,并更名為ehcache.xml

(1)<diskStore/>標(biāo)簽

指定一個(gè)文件目錄,當(dāng)內(nèi)存空間不夠,需要將二級(jí)緩存中數(shù)據(jù)寫到硬盤上時(shí),會(huì)寫到這個(gè)指定目錄中。其值一般為java.io.tmpdir,表示當(dāng)前系統(tǒng)的默認(rèn)文件臨時(shí)目錄。

當(dāng)前文件系統(tǒng)的默認(rèn)文件臨時(shí)目錄,可以通過System.property()方法查看:

@Test
public void test(){
 String path = System.getProperty("java.io.tmpdir");
 System.out.println(path);
}

(2)<defaultCache/>標(biāo)簽

3.啟用ehcache緩存機(jī)制

在映射文件的mapper中的<cache/>中通過type指定緩存機(jī)制為Ehcache緩存。默認(rèn)為MyBatis內(nèi)置的二級(jí)緩存org.apache.ibatis.cache.impl.PerpetualCache。

<mapper namespace="com.hcx.dao.IStudentDao">
 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  <select id=selectStudentById resultType="com.hcx.beans.Student">
   select * from student where id=#{id}
  </select>
</mapper>

4.ehcache在不同mapper中的個(gè)性化設(shè)置

在ehcache.xml中設(shè)置的屬性值,會(huì)對(duì)該項(xiàng)目中所有使用ehcache緩存機(jī)制的緩存區(qū)域起作用。一個(gè)項(xiàng)目中可以有多個(gè)mapper,不同的mapper有不同的緩存區(qū)域。對(duì)于不同緩存區(qū)域也可進(jìn)行專門針對(duì)于當(dāng)前區(qū)域的個(gè)性設(shè)置,可通過指定不同mapper的<cache>屬性值來設(shè)置。

<cache>屬性值的優(yōu)先級(jí)高于ehcache.xml中的屬性值。

<mapper namespace="com.hcx.dao.IStudentDao">
 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
   <property name="maxElementsInMemory" value="5000"/>
   <property name="timeToIdleSeconds" value="240"/>
 </cache>
</mapper>

以上所述是小編給大家介紹的MyBatis查詢緩存實(shí)例詳解,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java設(shè)計(jì)模式之java備忘錄模式詳解

    Java設(shè)計(jì)模式之java備忘錄模式詳解

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之備忘錄模式,簡(jiǎn)單說明了備忘錄模式的概念、原理并結(jié)合實(shí)例形式分析了java備忘錄模式的具體定義及使用方法,需要的朋友可以參考下
    2021-09-09
  • SpringBoot+hutool實(shí)現(xiàn)圖片驗(yàn)證碼

    SpringBoot+hutool實(shí)現(xiàn)圖片驗(yàn)證碼

    本文主要介紹了SpringBoot+hutool實(shí)現(xiàn)圖片驗(yàn)證碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 基于java TCP網(wǎng)絡(luò)通信的實(shí)例詳解

    基于java TCP網(wǎng)絡(luò)通信的實(shí)例詳解

    本篇文章是對(duì)java中TCP網(wǎng)絡(luò)通信的實(shí)例進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • java中MVC模式與三層架構(gòu)

    java中MVC模式與三層架構(gòu)

    這篇文章主要讓我們理解MVC模式和三層架構(gòu)的基礎(chǔ)知識(shí),有興趣的同學(xué)可以閱讀,借鑒參考一下
    2023-03-03
  • Java行為型模式中命令模式分析

    Java行為型模式中命令模式分析

    在軟件設(shè)計(jì)中,我們經(jīng)常需要向某些對(duì)象發(fā)送請(qǐng)求,但是并不知道請(qǐng)求的接收者是誰(shuí),也不知道被請(qǐng)求的操作是哪個(gè),我們只需在程序運(yùn)行時(shí)指定具體的請(qǐng)求接收者即可,此時(shí)可以使用命令模式來進(jìn)行設(shè)計(jì)
    2023-02-02
  • SpringBoot中的Mybatis依賴問題

    SpringBoot中的Mybatis依賴問題

    這篇文章主要介紹了SpringBoot中的Mybatis依賴問題,包括pom導(dǎo)入依賴和相關(guān)實(shí)例代碼講解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • spring security環(huán)境搭建

    spring security環(huán)境搭建

    本文通過代碼給大家介紹了spring security環(huán)境搭建的詳細(xì)教程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2017-09-09
  • Spring Security基于JWT實(shí)現(xiàn)SSO單點(diǎn)登錄詳解

    Spring Security基于JWT實(shí)現(xiàn)SSO單點(diǎn)登錄詳解

    這篇文章主要介紹了Spring Security基于JWT實(shí)現(xiàn)SSO單點(diǎn)登錄詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 16 個(gè)有用的的Java工具類(小結(jié))

    16 個(gè)有用的的Java工具類(小結(jié))

    這篇文章主要介紹了16 個(gè)有用的的Java工具類,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Spring Security OAuth2 授權(quán)碼模式的實(shí)現(xiàn)

    Spring Security OAuth2 授權(quán)碼模式的實(shí)現(xiàn)

    這篇文章主要介紹了Spring Security OAuth2 授權(quán)碼模式的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08

最新評(píng)論