mybatis提供查詢緩存,用於減輕數據壓力,提升數據庫性能
mybatis提供一級緩存二級緩存
一級緩存是SQLSession級別的緩存
在操做數據庫時須要構造SQLSession對象,在對象中有一個數據結構(HashMap)用戶存儲緩存數據
不一樣的SQLSession之間的緩存數據的區域(HashMap)是互不影響的。
二級緩存是mapper級別的緩存
多個SQLSession去操做同一個Mapper的sql語句,多個SqlSession能夠共用二級緩存,二級緩存是SQLSession的
爲何要存儲?
若是緩存中有數據就不用在從數據庫中獲取,大大提升系統的性能。
1234567891011121314複製代碼
2.1一級緩存的工做原理
第一次發起查詢用戶id爲1的用戶的信息,先去找緩存中是否有id爲1的用戶信息,若是沒有,從數據庫查詢用戶
信息
獲得用戶信息,將用戶信息存儲到一級存儲中
若是在SQLSession去執行commit操做(執行插入,更新,刪除)清空SQLSession中的一級緩存。這樣作的目的
爲了緩存中永遠存儲的是最新的信息,避免髒讀
第二次發起查詢用戶id爲1的用戶信息,先去查詢緩存中是否有id爲1的用戶信息,緩存中有,直接從緩存中獲取
用戶信息
2.2一級緩存測試
mybatis默認支持一級緩存,不須要在配置文件去配置
按照上邊一級緩存原理步驟測試
12345678910111213複製代碼
測試代碼
public testCacher1() throws Exception{
SqlSession sqlSesssion=sqlSessionFactory.openSession();//建立代理對象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//下邊查詢使用一個SqlSession
//第一次發起請求,查詢id爲1的用戶
User uyser=userMapper.findUserById(1);
System.out.println(:user1);
//若是SQLSession去執行commit操做(執行插入,更新,刪除) 清空SQLSession中的一級緩存
這樣作的目的是爲了讓緩存中存儲的是最新的信息,避main髒讀
//更新user的信息
user.setUsername(「測試用戶22」);
userMapper.updateUser(user1);
//執行commint操做去清除緩存
SQLSession.commit();
//第二次發起請求,查詢id爲1的用戶
User user2=username.fiondUserById(1);
System.out.println(user2);
sqlSession.close();
}123456789101112131415161718192021複製代碼
2.3一級緩存的應用
正式開發,是將mybatis和spring進行整合開發,事務空載子service中
一個service方法中包括不少mapper方法調用
service
//開始執行執行時,開啓事務,建立SQLSession對象
//第一調用mapper的方法findUserByID(1);
//第二次調用mapper的方法findUserByID(1);從一級緩存中取數據
//方法結束sqlSession關閉
若是是倆次service調用查詢相同的用戶信息,不走一級緩存,由於service方法結束,SQLSession就關閉
一級緩存就清空。
1234567891011複製代碼
首先開啓mybatis的二級緩存
SQLSession去查詢用戶id爲1的用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中
若是SQLSession去執行相同mapper下sql,執行commit提交,清空該mapper下的二級緩存區域的數據
SQLSession去查詢用戶id爲1的用戶信息,去緩存中查中是否存在數據,若是存在直接從緩存中取出數據
二級緩存與一級緩存區別:二級緩存的範圍更大,多個SQLSession能夠共享一個UserMapper二級緩存
UserMapper有一個二級緩存區域(按照namespace分),其餘的mapper也有本身的緩存區域(按照namespace分)
每個namespace的mapper有一個二級緩存區域,若是倆個mapper的namespace若是相同,這倆個
mapper執行sql查詢到的數據就存在相同的二級緩存區域中
3.1開啓二級緩存
12345678910複製代碼
mybatis的二級緩存是mapper範圍級別,除了在SqlMapConfig.xml設置二級緩存的總開關,還要在具體的mapper.xml
中開啓二級緩存
二級緩存使用,須要在主文件中進行配置:
①啓用二級緩存
<!-- 啓用二級緩存 -->
<setting name="cacheEnabled" value="true"/>
在UserMapper中開啓二級緩存,UserMapper.xml下的sql執行完成會存儲到它的緩存區域(HashMap)、
<mapper namespace="mybaties.mapper.User,apper">
<!--開啓本mapper的namespace下的二級緩存-->
<cache/>1234567891011複製代碼
3.2調用pojo類實現序列化接口
12複製代碼
public class User implements Serializables{
private int id;
private String username;
private String sex;
private Date birthday;
private String address;
}1234567複製代碼
爲了將緩存的數據取出執行序列化操做,由於二級緩存的存儲介質多種多樣,不必定在內存
3.3測試方法
1234複製代碼
public testCacher2() throws Exception{
SqlSession sqlSesssion=sqlSessionFactory.openSession();
SqlSession sqlSesssion2=sqlSessionFactory.openSession();
SqlSession sqlSesssion3=sqlSessionFactory.openSession();
//建立代理對象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//下邊查詢使用一個SqlSession
//第一次發起請求,查詢id爲1的用戶
User uyser=userMapper.findUserById(1);
System.out.println(:user1);
//這裏執行關閉操做,將SQLSession中的數據寫到二級緩存區域
SQLSession.close();
//使用SQLSession執行commit()操做
UserMapper userMapper3=sqlSession3.getMapper(UserMapper.class);
User user=userMapper3.findUserById(1);
user.setUsername(「測試用戶22」);
userMapper3.updateUser(user1);
//執行commint操做去清除緩存
SQLSession3.commit();
SQLSession3.close();
UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
//第二次發起請求,查詢id爲1的用戶
User user2=userMapper2.findUserById(1);
Stystem.out.println(user2);
sqlSession2.close();
}
123456789101112131415161718192021222324252627282930313233複製代碼
3.4useCache配置
①.設置useCache=false能夠禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認狀況是true,即該sql使用二級緩存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
總結:針對每次查詢都須要最新的數據sql,要設置成useCache=false,禁用二級緩存。
②.清空緩存
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
總結:通常下執行完commit操做都須要刷新緩存,flushCache=true表示刷新緩存,這樣能夠避免數據庫髒讀。
注意:
(1)當爲select語句時:
flushCache默認爲false,表示任什麼時候候語句被調用,都不會去清空本地緩存和二級緩存。
useCache默認爲true,表示會將本條語句的結果進行二級緩存。
(2)當爲insert、update、delete語句時:
flushCache默認爲true,表示任什麼時候候語句被調用,都會致使本地緩存和二級緩存被清空。
useCache屬性在該狀況下沒有。
當爲select語句的時候,若是沒有去配置flushCache、useCache,那麼默認是啓用緩存的,因此,若是有必要,那麼就須要人工修改配置
4.mybatis整合ehcache
4.1分佈式緩存
咱們系統爲了提升系統併發,性能。通常對系統進行分佈式部署。(集羣部署方式)
不使用分佈緩衝池緩存的數據在各自服務器單獨存儲,不方便系統開發,因此要對分佈式緩存對緩存數據進行集中管理
mybatis沒法實現分佈式緩存。須要和其餘分佈式緩存框架進行整合
4.2整合的方法
mybatis提供了一個cache接口,若是要實現本身的存儲邏輯,實現cache接口開發便可
mybatis和ehcache整合,mybatis和ehcache集合包中提供了一個cache接口的實現類
1234567891011121314151617181920212223242526272829303132複製代碼
public interface Cache{
String getId();
void putObject(Object key ,Object value);
Object getObject(Object key);
}
mybatis默認實現的cache類是
public class PerpetualCache implements Cache{
private String id;
private Map<Object,Object> cache=new HashMap<Object,Object>();
public PerpetualCache(String id){
this.id=id;
}
public String getId(){
return id;
}
}
123456789101112131415161718192021複製代碼
4.3配置信息
12複製代碼
配置mapper中的cache中的type爲ehcache對cache接口的實現
<mapper namespace="mybatis.mapper.UserMapper">
<!-- 開啓mapper的namespace下的二級緩存
type:指定Cache接口的實現類的類型,mybatis默認使用PerpetualCache
要和ehcache整合:須要配置type爲ehcache實現cache接口類型
-->
<caahe type="org.mybatis.caches.ehcache.EhcacheCache"/>1234567複製代碼
3.4加入ehcache包
ehcache-core-2.6.5.jar
mybatis-ehcache-1.0.2jar
3.5加入ehcache的配置文件
123456複製代碼
在classpath下配置
1 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
3 <diskStore path="F:\develop\ehcache" />
4 <defaultCache
5 maxElementsInMemory="1000"
6 maxElementsOnDisk="10000000"
7 eternal="false"
8 overflowToDisk="false"
9 timeToIdleSeconds="120"
10 timeToLiveSeconds="120"
11 diskExpiryThreadIntervalSeconds="120"
12 memoryStoreEvictionPolicy="LRU">
13 </defaultCache>
14 </ehcache> 123456789101112131415複製代碼
屬性說明:
diskStore:指定數據在磁盤中的存儲位置。
defaultCache:當藉助CacheManager.add("demoCache")建立Cache時,EhCache便會採用<defalutCache/>指定的的管理策略
如下屬性是必須的:
maxElementsInMemory - 在內存中緩存的element的最大數目
maxElementsOnDisk - 在磁盤上緩存的element的最大數目,如果0表示無窮大
eternal - 設定緩存的elements是否永遠不過時。若是爲true,則緩存的數據始終有效,若是爲false那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷
overflowToDisk - 設定當內存緩存溢出的時候是否將過時的element緩存到磁盤上
如下屬性是可選的:
timeToIdleSeconds - 當緩存在EhCache中的數據先後兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數據便會刪除,默認值是0,也就是可閒置時間無窮大
timeToLiveSeconds - 緩存element的有效生命期,默認是0.,也就是element存活時間無窮大
diskSpoolBufferSizeMB 這個參數設置DiskStore(磁盤緩存)的緩存區大小.默認是30MB.每一個Cache都應該有本身的一個緩衝區.
diskPersistent - 在VM重啓的時候是否啓用磁盤保存EhCache中的數據,默認是false。
diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每一個120s,相應的線程會進行一次EhCache中數據的清理工做
memoryStoreEvictionPolicy - 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出
4二級緩存應用場景
應用場景:
123456789101112131415161718複製代碼
對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術下降數據庫訪問量,提升訪
問速度,業務場景好比:耗時較高的統計分析sql、電話帳單查詢sql等。實現方法以下:經過設置刷新間隔時間,由mybatis每隔一段時
間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,好比設置爲30分鐘、60分鐘、24小時等,根據需求而定。spring
5.侷限性:
mybatis二級緩存對細粒度的數據級別的緩存實現很差,好比以下需求:對商品信息進行緩存,因爲商品信息查詢訪問量大,
可是要求用戶每次都能查詢最新的商品信息,此時若是使用mybatis的二級緩存就沒法實現當一個商品變化時只刷新該商品的緩
存信息而不刷新其它商品的信息,由於mybaits的二級緩存區域以mapper爲單位劃分,當一個商品信息變化會將全部商品信息
的緩存數據所有清空。解決此類問題須要在業務層根據需求對數據有針對性緩存。複製代碼