MyBatis框架:第十章:mybatis緩存

mybatis緩存
說明: 緩存指的是把一些常用的數(shù)據(jù),保存到一個可以高速讀取的緩沖區(qū)中。方便程序在頻繁讀取的時候,可以快速的取出數(shù)據(jù)。這就叫做緩存。

一級緩存指的是,這些緩存的數(shù)據(jù),在同一個SqlSession中多次SQL操作都可以獲取。

二級緩存指的是,這些緩存的數(shù)據(jù)。在同一個Mapper中有一個cache緩存對象。多個SqlSession對象可以共享這些數(shù)據(jù)。

15.1、mybatis的一級緩存

MyBatis的一級緩存默認開啟。同一個SqlSession中查詢,可以從一級緩存中取數(shù)據(jù)。

15.1.1、一級緩存的演示
創(chuàng)建實體Bean對象

public class User {
private int id;
private String lastName;
private int sex;

創(chuàng)建UserMapper接口

public interface UserMapper {
public User queryUserById(int id);
}

創(chuàng)建UserMappper配置文件

<!-- 
	queryUserById 根據(jù)id查詢用戶
 -->
<select id="queryUserById" parameterType="int" resultType="com.bean.User">
	select id,last_name lastName,sex  from t_user where id = #{id}
</select>

測試一級緩存的測試代碼:

@Test
public void testQueryUserById() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserById(1);
System.out.println(user);
User user1 = userMapper.queryUserById(1);
System.out.println(user1);
} finally {
session.close();
}
}

測試的結(jié)果:
在這里插入圖片描述

在上面的測試代碼中,我們不難看出。我們查詢了兩次??墒侵话l(fā)出一條sql語句。
這是由于第二次查詢的時候,是直接從一級緩存中取出的數(shù)據(jù)。而沒有查詢數(shù)據(jù)庫。

15.1.2、一級緩存的管理
緩存失效的四種情況:
1.不在同一個SqlSession對象中
2.執(zhí)行語句的參數(shù)不同。緩存中也不存在數(shù)據(jù)。
3.執(zhí)行增,刪,改,語句,會清空掉緩存
4.手動清空緩存數(shù)據(jù)
15.1.2.1、不在同一個緩存對象中(SqlSession或SqlSessionFactory)
測試的代碼:

@Test
public void testCacheFail1() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserById(1);
System.out.println(user);
} finally {
session.close();
}

SqlSession session2 = sqlSessionFactory.openSession();
try {
	UserMapper userMapper =  session2.getMapper(UserMapper.class);
	User user = userMapper.queryUserById(1);
	System.out.println(user);
} finally {
	session2.close();
}

}

測試的結(jié)果:
在這里插入圖片描述

15.1.2.2、執(zhí)行語句的參數(shù)不同。緩存中也不存在數(shù)據(jù)。
測試的代碼:

@Test
public void testCacheFail2() {

SqlSession session = sqlSessionFactory.openSession();
try {
	UserMapper userMapper = session.getMapper(UserMapper.class);			
	System.out.println( userMapper.queryUserById(1) );
	System.out.println( userMapper.queryUserById(2) );
	
} finally {
	session.close();
}

}

測試的結(jié)果:
在這里插入圖片描述

15.1.2.3、執(zhí)行增,刪,改,語句,會清空掉緩存
增加的更新方法

public int updateUser(User user);

增加的方法對應(yīng)的xml配置

<update id="updateUser" parameterType="com.bean.User">
	update t_user set last_name = #{lastName} , sex = #{sex} where id = #{id}
</update>

測試的代碼:

@Test
public void testCacheFail3() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
System.out.println( userMapper.queryUserById(1) );
userMapper.updateUser(new User(2, “2xxxxx”, 1));
System.out.println( userMapper.queryUserById(1) );
session.commit();
} finally {
session.close();
}
}

測試的結(jié)果:
在這里插入圖片描述

15.1.2.4、手動清空緩存數(shù)據(jù)
測試的代碼:

@Test
public void testCacheFail4() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
System.out.println( userMapper.queryUserById(1) );
session.clearCache();
System.out.println( userMapper.queryUserById(1) );
session.commit();
} finally {
session.close();
}
}

測試的結(jié)果:
在這里插入圖片描述

15.2、mybatis的二級緩存

二級緩存的圖解示意
在這里插入圖片描述

二級緩存的使用:
myBatis的二級緩存默認是不開啟的。我們需要在mybatis的核心配置文件中配置setting選項 和 在Mapper的配置文件中加入cache標(biāo)簽。并且需要被二級緩存的對象必須要實現(xiàn)java的序列化接口。

一:配置全局的setting

<!-- 啟用二級緩存  -->
<setting name="cacheEnabled" value="true"/>

二:在需要使用二級緩存的Mapper配置文件中加入cache標(biāo)簽

<!-- cache標(biāo)簽配置二級緩存 -->
<cache></cache>

三:需要二級緩存的數(shù)據(jù)對象必須要實現(xiàn)序列化接口java.io.Serializable

15.2.1、二級緩存的演示
示例代碼:

@Test
public void testQueryUserById() {
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserById(1);
System.out.println(user);
session.close();
SqlSession session1 = sqlSessionFactory.openSession();
UserMapper userMapper1 = session1.getMapper(UserMapper.class);
user = userMapper1.queryUserById(1);
System.out.println(user);
session1.close();
}

查詢結(jié)果:
在這里插入圖片描述

15.2.2、useCache="false"的演示和說明
在Mapper配置文件的定義select查詢語句的標(biāo)簽中,可以給某個select查詢語句定義不使用二級緩存。

這個時候,咱們再執(zhí)行上次的二級緩存查詢測試代碼,得到的結(jié)果如下:
在這里插入圖片描述

15.2.3、flushCache="true"的演示和說明
默認情況下,在所有的insert。update。delete標(biāo)簽中,都有flushCache=”true”。這樣的屬性。
表示當(dāng)要執(zhí)行增,刪,改語句的時候,都需要清空緩存中的數(shù)據(jù)。清空之后,再次的查詢就不會從二級緩存中獲取數(shù)據(jù)。
這樣做的好處是為了避免出現(xiàn)臟讀的情況。

增,刪,改清空緩存的測試代碼。

@Test
public void testQueryUserById2() {
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.queryUserById(1);
System.out.println(user);
session.close();

SqlSession session2 = sqlSessionFactory.openSession();
UserMapper userMapper2 = session2.getMapper(UserMapper.class);
userMapper2.updateUser(new User(1, "更新了", 1));
session2.commit();
session2.close();

SqlSession session1 = sqlSessionFactory.openSession();
UserMapper userMapper1 = session1.getMapper(UserMapper.class);
user = userMapper1.queryUserById(1);
System.out.println(user);
session1.close();

}

查詢的結(jié)果:
在這里插入圖片描述

當(dāng)我們把update標(biāo)簽上的屬性改為 flushCache=“false” 的時候。就會出現(xiàn)臟讀的情況。
update t_user set last_name = #{lastName} , sex = #{sex} where id = #{id}

再次執(zhí)行上面清空緩存的測試代碼。就會出現(xiàn)臟讀的情況。
在這里插入圖片描述

15.2.4、標(biāo)簽的介紹和說明
默認的標(biāo)簽的作用:
1、映射語句文件中的所有 select 語句將會被緩存。
2、射語句文件中的所有 insert,update 和 delete 語句會刷新緩存。
3、緩存會使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
4、根據(jù)時間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會以任何時間順序 來刷新。
5、緩存會存儲列表集合或?qū)ο?無論查詢方法返回什么)的 1024 個引用。
6、緩存會被視為是 read/write(可讀/可寫)的緩存,意味著對象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。

cache標(biāo)簽示例解析:

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

eviction 屬性表示緩存策略。

LRU – 最近最少使用的:移除最長時間不被使用的對象(這是默認策略)。
FIFO – 先進先出:按對象進入緩存的順序來移除它們。
SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對象。
WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象。

flushInterval 屬性表示間隔多長時間刷新一下緩沖區(qū),清理一下溢出的數(shù)據(jù)。以毫秒為單位。
size 屬性表示緩存中可以保存多少個對象。默認是1024。
readOnly 屬性表示是否只讀。如果設(shè)置為true。表示緩存中只有一個對象。如果設(shè)置為false(默認為false)每次取出來都會反序列化拷貝一份。
type 屬性表示自定義二級緩存對象。

15.2.6、EhCache緩存的使用
EhCache緩存介紹:
EhCache 是一個專業(yè)的純Java的進程緩存框架。具有快速、精干等特點,是Hibernate中默認的CacheProvider緩存提供者。
由于MyBatis中定義了Cache緩存接口極大的方便了我們對緩存的自定義切換和擴展。

整合EhCache到MyBatis的步驟:
1.導(dǎo)入ehcache的包。以及整合包。
在這里插入圖片描述在這里插入圖片描述在這里插入圖片描述在這里插入圖片描述












2.編寫ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
 <!-- 磁盤保存路徑 -->
 <diskStore path="D:\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="1000" 
   maxElementsOnDisk="10000000"
   eternal="false" 
   overflowToDisk="true" 
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 </defaultCache>
</ehcache>
 
<!-- 
屬性說明:
l diskStore:指定數(shù)據(jù)在磁盤中的存儲位置。
 
以下屬性是必須的:
l maxElementsInMemory - 在內(nèi)存中緩存的element的最大數(shù)目 
l maxElementsOnDisk - 在磁盤上緩存的element的最大數(shù)目,若是0表示無窮大
l eternal - 設(shè)定緩存的elements是否永遠不過期。如果為true,則緩存的數(shù)據(jù)始終有效,如果為false那么還要根據(jù)timeToIdleSeconds,timeToLiveSeconds判斷
l overflowToDisk - 設(shè)定當(dāng)內(nèi)存緩存溢出的時候是否將過期的element緩存到磁盤上
 
以下屬性是可選的:
l timeToIdleSeconds - 當(dāng)緩存在EhCache中的數(shù)據(jù)前后兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數(shù)據(jù)便會刪除,默認值是0,也就是可閑置時間無窮大
l timeToLiveSeconds - 緩存element的有效生命期,默認是0.,也就是element存活時間無窮大
 diskSpoolBufferSizeMB 這個參數(shù)設(shè)置DiskStore(磁盤緩存)的緩存區(qū)大小.默認是30MB.每個Cache都應(yīng)該有自己的一個緩沖區(qū).
l diskPersistent - 在VM重啟的時候是否啟用磁盤保存EhCache中的數(shù)據(jù),默認是false。
l diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每個120s,相應(yīng)的線程會進行一次EhCache中數(shù)據(jù)的清理工作
    l memoryStoreEvictionPolicy - 當(dāng)內(nèi)存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出)

 -->

3.配置cache標(biāo)簽的type屬性

<cache type="org.mybatis.caches.ehcache.EhcacheCache" />

16、緩存的使用順序說明:
1、當(dāng)我們執(zhí)行一個查詢語句的時候。mybatis會先去二級緩存中查詢數(shù)據(jù)。如果二級緩存中沒有。就到一級緩存中查找。
2、如果二級緩存和一級緩存都沒有。就發(fā)sql語句到數(shù)據(jù)庫中去查詢。
3、查詢出來之后馬上把數(shù)據(jù)保存到一級緩存中。
4、當(dāng)SqlSession關(guān)閉的時候,會把一級緩存中的數(shù)據(jù)保存到二級緩存中。