1.什么是查詢緩存

mybatis提供查詢緩存,用于減輕數(shù)據(jù)庫壓力,提高數(shù)據(jù)庫性能。

mybatis提供一級緩存和二級緩存。

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

一級緩存是SqlSession級別的緩存。在操作數(shù)據(jù)庫時需要構(gòu)造sqlSession對象,在對象中有一個數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。

二級緩存是mapper級別的緩存,多個sqlSession去操作同一個Mapper的sql語句,多個sqlSession可以共用二級緩存,二級緩存是跨sqlSession的。

為什么要用緩存?

如果緩存中有數(shù)據(jù)就不用從數(shù)據(jù)庫中獲取,大大提高系統(tǒng)性能。

2.一級緩存

2.1一級緩存工作原理

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

 第一次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數(shù)據(jù)庫查詢用戶信息。

得到用戶信息,將用戶信息存儲到一級緩存中。

如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空sqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。

第二次發(fā)去查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。

 2.2一級緩存測試

 mybatis默認支持一級緩存,不需要在配置文件去配置。

 按照上邊一級緩存原理步驟去測試。

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

 @Test     public void testCache1() throws Exception{         SqlSession sqlSession=sqlSessionFactory.openSession();         UserMapper userMapper=sqlSession.getMapper(UserMapper.class);         //下邊查詢使用一個SqlSession         //第一次發(fā)起請求,查詢id為1的用戶         User user1=userMapper.findUserById(1);         System.out.println(user1);                  //如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空sqlSession中的一級緩存,         //這樣做的目的是為了讓緩存中存儲的是最新的信息,避免臟讀。         //更新user1的信息         user1.setUsername("測試用戶22");         userMapper.updateUser(user1);         //執(zhí)行commit操作去清空緩存         sqlSession.commit();                  //第二次發(fā)起請求,查詢id為1的用戶         User user2=userMapper.findUserById(1);         System.out.println(user2);         sqlSession.close();     }

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

2.3一級緩存應(yīng)用

 正式開發(fā),是將mybatis和spring進行整合開發(fā),事務(wù)控制在service中。

一個service方法中包括很多Mapper方法調(diào)用。

service{

  //開始執(zhí)行時,開啟事務(wù),創(chuàng)建SqlSession對象

  //第一次調(diào)用mapper的方法findUserById(1)

 

  //第二次調(diào)用mapper的方法findUserById(1),從一級緩存中取數(shù)據(jù)

  //方法結(jié)束,sqlSession關(guān)閉

}

如果是執(zhí)行兩次service調(diào)用查詢相同的用戶信息,不走一級緩存,因為session方法結(jié)束,sqlSession就關(guān)閉,一級緩存就清空。

3.二級緩存

3.1二級緩存原理

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

首先開啟mybatis的二級緩存。

sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息后悔講查詢數(shù)據(jù)存儲到二級緩存中。

如果sqlSession3去執(zhí)行相同mapper下的sql,執(zhí)行commit提交,會清空該mapper下的二級緩存區(qū)域的數(shù)據(jù)。

sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)。

二級緩存與一級緩存區(qū)別:二級緩存的范圍更大,多個sqlSession可以共享一個UserMapper的二級緩存區(qū)域。UserMapper有一個二級緩存區(qū)域(按namespace分),其它mapper也有自己的二級緩存區(qū)域(按namespace分)。

每個namespace的mapper都有一個二級緩存區(qū)域,兩個mapper的namespace如果相同,這兩個mapper執(zhí)行sql查詢到的數(shù)據(jù)將存在相同的二級緩存區(qū)域中。

3.2開啟二級緩存

mybatis的二級緩存是mapper范圍級別,除了在SqlMapConfig.xml設(shè)置二級緩存的總開關(guān),還要在具體的mapper.xml中開啟二級緩存。

在核心配置文件SqlMapConfig.xml中加入:

<setting name="cacheEnabled" value="true"/>

描述允許值默認值
cacheEnabled對在此配置文件下的所有cache 進行全局性開/關(guān)設(shè)置。true false false

 

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

在UserMapper.xml中開啟二級緩存,UserMapper.xml下的sql執(zhí)行完成后存儲在它的緩存區(qū)域(HashMap)。

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

3.3調(diào)用pojo類實現(xiàn)序列化接口

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

為了將緩存數(shù)據(jù)取出執(zhí)行反序列劃操作,因為二級緩存數(shù)據(jù)存儲介質(zhì)多種多樣,不一定在內(nèi)存。可能在硬盤、遠程等。

3.4測試方法

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

    @Test     public void testCache2() throws Exception{         SqlSession sqlSession1=sqlSessionFactory.openSession();         SqlSession sqlSession2=sqlSessionFactory.openSession();         SqlSession sqlSession3=sqlSessionFactory.openSession();                  UserMapper userMapper1=sqlSession1.getMapper(UserMapper.class);         UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);         UserMapper userMapper3=sqlSession3.getMapper(UserMapper.class);                  //第一次發(fā)起請求,查詢id為1的用戶         User user1=userMapper1.findUserById(1);         System.out.println(user1);         //這里執(zhí)行關(guān)閉操作,將sqlSession中的數(shù)據(jù)寫到二級緩存區(qū)域         sqlSession1.close();                  //使用sqlSession3執(zhí)行commit()操作         User user=userMapper3.findUserById(1);         user1.setUsername("Joanna");         userMapper3.updateUser(user);         //執(zhí)行提交,清空UserMapper下邊的二級緩存         sqlSession3.commit();         sqlSession3.close();                  //第二次發(fā)起請求,查詢id為1的用戶         User user2=userMapper2.findUserById(1);         System.out.println(user2);         sqlSession2.close();     }

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

3.5禁用二級緩存

在statement中設(shè)置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發(fā)出sql,默認情況是true,即該sql使用二級緩存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

3.6刷新緩存(就是清空緩存)

 在mapper的同一個namespace中,如果有其它insert、update、delete操作數(shù)據(jù)后需要刷新緩存,如果不執(zhí)行刷新緩存會出現(xiàn)臟讀。

設(shè)置statement配置中的flushCache="true"屬性,默認情況下為true即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動修改數(shù)據(jù)庫表中的查詢數(shù)據(jù)會出現(xiàn)臟讀。

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

 總結(jié):一般情況下執(zhí)行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數(shù)據(jù)庫臟讀。

3.7 Mybatis Cache參數(shù)

flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個合理的毫秒形式的時間端。默認情況是不設(shè)置,也局勢沒有刷新間隔,緩存僅僅調(diào)用語句時刷新。

size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對象數(shù)目和你運行環(huán)境的可用內(nèi)存資源數(shù)目。默認值是1024。

readOnly(只讀)屬性可以被設(shè)置為true或false。只讀的緩存會給所有調(diào)用者返回緩存對象的相同實例。因此這些對象不能被修改。這提供了很重要的性能優(yōu)勢??勺x寫的緩存會返回緩存對象的拷貝(通過序列化)。這會慢一些,但是安全,因此默認是false。

如下例子:

<cache  eviction="FIFO"  flushInterval="60000"  size="512"  readOnly="true"/>

這個更高級的配置創(chuàng)建了一個 FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對象或列表的 512 個引用,而且返回的對象被認為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會導致沖突。可用的收回策略有, 默認的是 LRU:

  1. LRU – 最近最少使用的:移除最長時間不被使用的對象。

  2. FIFO – 先進先出:按對象進入緩存的順序來移除它們。

  3. SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象。

  4. WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象。

4.mybatis整合ehcache

ehcache是一個純Java的進程內(nèi)緩存框架,是一種廣泛使用的開源Java分布式緩存,具有快速、精干等特點,是Hibernate中默認的CacheProvider。

4.1分布式緩存

為了提高系統(tǒng)并發(fā)、性能,一般會系統(tǒng)進行分布式部署(集群部署方式)

 

 

 

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

不使用分布式緩存,緩存的數(shù)據(jù)在各個服務(wù)單獨存儲,不方便系統(tǒng)開發(fā)。所以要使用分布式緩存對緩存數(shù)據(jù)進行集中管理。

mybatis的特長是sql操作,緩存數(shù)據(jù)的管理不是mybatis的特長。mybatis無法實現(xiàn)分布式緩存,需要和其它分布式緩存框架進行整合,如:redis、memcached、ehcache等。

4.2整合方法(掌握)

mybatis提供了一個cache接口,如果要實現(xiàn)自己的緩存邏輯,實現(xiàn)cache接口開發(fā)即可。

mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個cache接口的實現(xiàn)類。

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

mybatis默認的cache實現(xiàn)類是:

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

4.3加入ehcache包

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

4.4整合ehcache

配置mapper中cache中的type為ehcache對cache接口的實現(xiàn)類型。

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

4.5加入ehcache的配置文件

在classpath下配置ehcache.xml

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">     <diskStore path="F:\develop\ehcache" />     <defaultCache          maxElementsInMemory="1000"          maxElementsOnDisk="10000000"         eternal="false"          overflowToDisk="false"          timeToIdleSeconds="120"         timeToLiveSeconds="120"          diskExpiryThreadIntervalSeconds="120"         memoryStoreEvictionPolicy="LRU">     </defaultCache> </ehcache>

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設(shè)計培訓,網(wǎng)站建設(shè)培訓

屬性說明:

diskStore:指定數(shù)據(jù)在磁盤中的存儲位置。

defaultCache:當借助CacheManager.add(“demoCache”)創(chuàng)建Cache時,EhCache便會采用<defaultCache/>指定的管理策略。

以下屬性是必須的:

maxElementsInMemory :在內(nèi)存中緩存的element的最大數(shù)目。

maxElementsOnDisk :在磁盤上緩存的element的最大數(shù)目,若是0表示無窮大。

eternal :設(shè)定緩存的elements是否永遠不過期。如果為true,則緩存的數(shù)據(jù)始終有效,如果為false,你們還要根據(jù)timeToIdleSeconds、timeToLiveSeconds判讀。

overflowToDisk :設(shè)定當內(nèi)存緩存溢出的時候是否將過期的element緩存到磁盤上。

以下屬性是可選的:

timeToIdleSeconds :當緩存在EhCache中的數(shù)據(jù)前后兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數(shù)據(jù)便會刪除,默認值是0,也就是可閑置時間無窮大。

timeToLiveSeconds :緩存element的有效生命期,默認是0,也就是element存活時間無窮大。

diskSpoolBufferSizeMB :這個參數(shù)設(shè)置DiskStore(磁盤緩存)的緩存區(qū)大小。默認是30MB,每個Cache都應(yīng)該有自己的一個緩沖區(qū)。

diskPersistent :在VM重啟的時候是否啟用磁盤保存EhCache中的數(shù)據(jù),默認是false。

diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每個120s,相應(yīng)的線程會進行一次EhCache中數(shù)據(jù)的清理工作。

memoryStoreEvictionPolicy - 當內(nèi)存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出)。

4.6測試程序

同3.4

4.7二級緩存應(yīng)用場景

 對訪問多的查詢請求且用戶對查詢結(jié)果實時性要求不高,此時可采用mybatis二級緩存技術(shù)降低數(shù)據(jù)庫訪問量,提高訪問速度,業(yè)務(wù)場景比如:耗時較高的統(tǒng)計分析sql、電話賬單查詢sql等。

實現(xiàn)方法如下:通過設(shè)置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據(jù)數(shù)據(jù)變化頻率設(shè)置緩存刷新間隔flushInterval,比如設(shè)置為30分鐘、60分鐘、24小時等,根據(jù)需求而定。

4.8二級緩存局限性

 mybatis二級緩存對細粒度的數(shù)據(jù)級別的緩存實現(xiàn)不好,比如如下需求:對商品信息進行緩存,由于商品信息查詢訪問量大,但是要求用戶每次都能查詢最新的商品信息,此時如果使用mybatis的二級緩存就無法實現(xiàn)當一個商品變化時只刷新該商品的緩存信息而不刷新其它商品的信息,因為mybatis的二級緩存區(qū)域以mapper為單位劃分,當一個商品信息變化會將所有商品信息的緩存數(shù)據(jù)全部清空。解決此類問題需要再業(yè)務(wù)層根據(jù)需求對數(shù)據(jù)有針對性緩存。

 

早年同窗始相知,三載瞬逝情卻萌。年少不知愁滋味,猶讀紅豆生南國。別離方知相思苦,心田紅豆根以生。

http://www.cnblogs.com/shanheyongmu/p/7125405.html