一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - MyBatis查詢緩存實例詳解

MyBatis查詢緩存實例詳解

2020-11-19 10:24我可能是個假開發 Java教程

查詢緩存的使用,主要是為了提高查詢訪問速度。這篇文章主要介紹了MyBatis查詢緩存,需要的朋友可以參考下

查詢緩存的使用,主要是為了提高查詢訪問速度。將用戶對同一數據的重復查詢過程簡化,不再每次均從數據庫查詢獲取結果數據,從而提高訪問速度。

mybatis的查詢緩存機制,根據緩存區的作用域(生命周期)可劃分為兩種:一級緩存與二級緩存

一、一級查詢緩存

mybatis一級緩存是基于org.apache.ibatis.cache.impl.perpetualcache類的hashmap本地緩存,其作用域是sqlsession。在同一個sqlsession中兩次執行相同的sql語句,第一次執行完畢后,會將查詢結果寫入到緩存中,第二次會從緩存中直接獲取數據,而不再到數據庫中進行查詢,從而提高查詢效率。

當一個sqlsession結束后,該sqlsession中的一級緩存也就不存在了。mybatis默認一級緩存是開啟狀態,且不能關閉。

MyBatis查詢緩存實例詳解

1.一級緩存的存在性證明

測試類:

?
1
2
3
4
5
6
7
8
9
10
//證明一級緩存的存在
@test
public void test01(){
 //第一次查詢
 student student = dao.selectstudentbyid(2);
 system.out.println(student);
 //第二次查詢
 student student2 = dao.selectstudentbyid(2);
 system.out.println(student2); 
}

mapper:

?
1
2
3
4
5
<mapper namespace="com.hcx.dao.istudentdao"
  <select id=selectstudentbyid resulttype="com.hcx.beans.student">
   select * from student where id=#{id}
  </select>
</mapper>

控制臺:

執行完后,發現只執行了一次從db中的查詢,第二次的結果是直接輸出的。說明,第二次是從sqlsession緩存中讀取的。

MyBatis查詢緩存實例詳解

2.從緩存讀取數據的依據是sql的id

一級緩存緩存的是相同sql映射id的查詢結果,而非相同sql語句的查詢結果。因為mybatis內部對于查詢緩存,無論是一級查詢還是二級查詢,其底層均使用一個hashmap實現:key為sql的id相關內容,value為從數據庫中查詢出的結果。

mapper:

?
1
2
3
4
5
6
7
8
<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接口:

?
1
2
3
4
public interface istudentdao { 
 student selectstudentbyid(int id);
 student selectstudentbyid2(int id);
}

測試類:

?
1
2
3
4
5
6
7
8
9
10
11
//證明從一級緩存中讀取數據的依據:
//mybatis:sql的id+sql語句
//hibernate:查詢結果對象的id
@test
public void test02(){
 student student = dao.selectstudentbyid(2);
 system.out.println(student);
 
 student student2 = dao.selectstudentbyid2(2);
 system.out.println(student2); 
}

控制臺:

查看控制臺,發現第二次查詢結果與第一次的完全相同,但第二次查詢并沒有從緩存中讀取數據,而是直接從db中進行的查詢。這是因為從緩存讀取數據的依據是查詢sql的映射id,而非查詢結果。

MyBatis查詢緩存實例詳解

3.增刪改對一級查詢緩存的影響

增刪改操作,無論是否進行提交sqlsession.commit(),均會清空一級查詢緩存,使查詢再次從db中select。

測試類:

?
1
2
3
4
5
6
7
8
9
@test
public void test03(){
 student student = dao.selectstudentbyid(2);
 system.out.println(student);
 //增刪改操作都會清空一級緩存,無論是否提交
 dao.insertstudent(new student("趙六",26,96.6));
 student student2 = dao.selectstudentbyid(2);
 system.out.println(student2); 
}

控制臺:

MyBatis查詢緩存實例詳解

二、內置二級查詢緩存

mybatis查詢緩存的作用域是根據映射文件mapper的namespace劃分的,相同namespace的mapper查詢數據存放在同一個緩存區域。不同namespace下的數據互不干擾。

無論是一級緩存還是二級緩存,都是按照namespace進行分別存放的。但一、二級緩存的不同之處在于,sqlsession一旦關閉,則sqlsession中的數據將不存在,即一級緩存就不復存在。而二級緩存的生命周期會與整個應用同步,與sqlsession是否關閉無關。

使用二級緩存的目的,不是共享數據,因為mybatis從緩存中讀取數據的依據是sql的id,而非查詢出的對象。所以,二級緩存中的數據不是為了在多個查詢之間共享(所有查詢中只要查詢結果中存在該對象的,就直接從緩存中讀取,這是對數據的共享,hibernate中的緩存就是為了共享,但mybatis不是),而是為了延長該查詢結果的保存時間,提高系統性能。

1.二級緩存用法

二級緩存的使用只需要完成兩步:

序列化實體

在mapper映射文件中添加<cache/>標簽

1.實體序列化

要求查詢結果所涉及到的實體類要實現java.io.serializable接口。若該實體類存在父類,或其具有域屬性,則父類與域屬性類也要實現序列化接口。

?
1
2
3
4
5
6
public class student implements serializable{
 private integer id;
 private string name;
 private int age;
 private double score;
}

2.mapper映射文件中添加<cache/>標簽

在mapper映射文件中的<mapper/>標簽中添加<cache/>子標簽

?
1
2
3
4
5
6
<mapper namespace="com.hcx.dao.istudentdao">
 <cache/>
  <select id=selectstudentbyid resulttype="com.hcx.beans.student">
   select * from student where id=#{id}
  </select>
</mapper>

3.二級緩存的配置

為<cache/>標簽添加一些相關屬性設置,可以對二級緩存的運行性能進行控制。若不指定設置,則均保持默認值。

?
1
2
<cache eviction="ifio" flushinterval="10800000"
  readonly="true" size="512"/>

eviction:逐出策略。當二級緩存中的對象達到最大值時,就需要通過逐出策略將緩存中的對象移出緩存。默認為lru。常用的策略有fifo和lru

flushinterval:刷新緩存的時間間隔,單位毫秒。這里的刷新緩存即清空緩存。一般不指定,即當執行增刪改時刷新緩存。

readonly:設置緩存中數據是否只讀。只讀的緩存會給所有調用者返回緩存對象的相同實例,因此這些對象不能被修改,這提供了很重要的性能優勢。但讀寫的緩存會返回緩存對象的拷貝。這會慢一些,但是安全,因此默認是false。
size:二級緩存中可以存放的最多對象個數。默認為1024個。

2.二級緩存的存在性證明

對于映射文件中的同一個查詢,肯定是同一個namespace中的查詢。在一次查詢后,將sqlsession關閉,再進行一次相同查詢,發現并沒有到db中進行select查詢,說明二級緩存是存在的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
//證明二級緩存的存在
@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); 
}

查看控制臺:

cache hit ratio表示緩存命中率。開啟二級緩存后,每執行一次查詢,系統都會計算一次二級緩存的命中率。第一次查詢也是先從緩存中查詢,只不過緩存中一定是沒有的。所以會再從db中查詢。由于二級緩存中不存在該數據,所以命中率為0.但第二次查詢是從二級緩存中讀取的,所以這一次的命中率為1/2=0.5。當然,若有第三次查詢,則命中率為1/3=0.66

MyBatis查詢緩存實例詳解

3.增刪改對二級緩存的影響

增刪改操作,無論是否進行提交sqlsession.commit(),均會清空一級、二級緩存,使查詢再次從db中select。

測試類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@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); 
}

控制臺:

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

MyBatis查詢緩存實例詳解

說明:

二級緩存的清空,實質上是對所查找key對應的value置為null,而非將<key,value>對,即entry對象刪除。

從db中進行select查詢的條件是:緩存中根本不存在這個key或者緩存中存在該key所對應的entry對象,但value為null。

設置增刪改操作不刷新二級緩存:

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

?
1
2
3
<insert id="insertstudent" flushcache="false">
  insert into student(name,age,score) values(#{name},#{age},#{score})
 </insert>

4.二級緩存的關閉

二級緩存默認為開啟狀態。若要將其關閉,則需要進行相關設置。
根據關閉的范圍大小,可以分為全局關閉和局部關閉

1.全局關閉(在配置文件中設置)

全局關閉是指整個應用的二級緩存全部關閉,所有查詢均不使用二級緩存。全局開關設置在主配置文件的全局設置<settings/>中,該屬性為cacheenabled,設置為false,則關閉;設置為true,則開啟,默認值為true。即二級緩存默認是開啟的。

?
1
2
3
4
<!-- 關閉二級緩存 -->
<settings>
 <setting name="cacheenabled" value="false"/>
</settings>

2.局部關閉(在映射文件的每個select中設置)

局部關閉指整個應用的二級緩存是開啟的,但只是針對某個<select/>查詢,不使用二級緩存。此時可以單獨只關閉該<select/>標簽的二級緩存。

在該要關閉二級緩存的<select/>標簽中,將其屬性usecache設置為false,即可關閉該查詢的二級緩存。該屬性默認為true,即每個<select/>查詢的二級緩存默認是開啟的。

?
1
2
3
4
<!--usecache="false"對當前sql的二級緩存的局部關閉 -->
 <select id=selectstudentbyid usecache="false" resulttype="com.hcx.beans.student">
  select * from student where id=#{id}
 </select>

5.二級緩存的使用原則

1.只能在一個命名空間下使用二級緩存

由于二級緩存中的數據是基于namespace的,即不同namespace中的數據互不干擾。在多個namespace中若均存在對同一個表的操作,那么這多個namespace中的數據可能就會出現不一致現象。

2.在單表上使用二級緩存

如果一個表與其它表有關聯關系,那么久非常有可能存在多個namespace對同一數據的操作。而不同namespace中的數據互補干擾,所以就有可能出現多個namespace中的數據不一致現象。

3.查詢多于修改時使用二級緩存

在查詢操作遠遠多于增刪改操作的情況下可以使用二級緩存。因為任何增刪改操作都將刷新二級緩存,對二級緩存的頻繁刷新將降低系統性能。

三、ehcache二級查詢緩存

mybatis允許使用第三方緩存產品。ehcache就是其中一種。

注意:使用ehcache二級緩存,實體類無需實現序列化接口。

1.導入jar包

MyBatis查詢緩存實例詳解

2.添加ehcache.xml

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

(1)<diskstore/>標簽

指定一個文件目錄,當內存空間不夠,需要將二級緩存中數據寫到硬盤上時,會寫到這個指定目錄中。其值一般為java.io.tmpdir,表示當前系統的默認文件臨時目錄。

MyBatis查詢緩存實例詳解

當前文件系統的默認文件臨時目錄,可以通過system.property()方法查看:

?
1
2
3
4
5
@test
public void test(){
 string path = system.getproperty("java.io.tmpdir");
 system.out.println(path);
}

(2)<defaultcache/>標簽

MyBatis查詢緩存實例詳解

MyBatis查詢緩存實例詳解

3.啟用ehcache緩存機制

在映射文件的mapper中的<cache/>中通過type指定緩存機制為ehcache緩存。默認為mybatis內置的二級緩存org.apache.ibatis.cache.impl.perpetualcache。

?
1
2
3
4
5
6
<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中的個性化設置

在ehcache.xml中設置的屬性值,會對該項目中所有使用ehcache緩存機制的緩存區域起作用。一個項目中可以有多個mapper,不同的mapper有不同的緩存區域。對于不同緩存區域也可進行專門針對于當前區域的個性設置,可通過指定不同mapper的<cache>屬性值來設置。

<cache>屬性值的優先級高于ehcache.xml中的屬性值。

?
1
2
3
4
5
6
<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查詢緩存實例詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:http://www.jianshu.com/p/90a34862dcdc

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美性色欧美a在线播放 | 亚洲AV蜜桃永久无码精品红樱桃 | 欧美日韩1区2区 | 欧美日韩中文国产一区二区三区 | 36美女厕所撒尿全过程 | 日本中文字幕一区二区高清在线 | 精品卡1卡2卡三卡免费网站 | 九九艹 | 4455在线| 亚洲精品视频免费在线观看 | 日本在线视频免费观看 | 国产欧美日韩精品一区二区三区 | 三上悠亚国产精品一区 | 国产色司机在线视频免费观看 | 精品国产成人a区在线观看 精品国产91久久久久久久 | 麻豆天美精东果冻传媒在线 | 国内精品久久久久久久久 | 欧美一级专区免费大片 | 免费国产成人α片 | www视频免费观看 | 成人免费影 | 午夜理论电影在线观看亚洲 | 久久99热狠狠色一区二区 | 加勒比福利 | ak福利影院| 99视频精品全部 在线 | 丰满肥臀风间由美357在线 | 国产精品一二三 | 国产香蕉久久 | 免费一级毛片在线播放 | 欧美日韩亚洲第一区在线 | 护士让我吃奶我扒她奶 | 亚洲人成在线播放 | 久久精品成人免费看 | segou视频在线观看 | 国产剧情一区二区三区 | 亚洲欧美韩国日产综合在线 | 2022最新a精品视频在线观看 | 久久久久嫩草影院精品 | 91在线免费看 | 欧美亚洲另类综合 |