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ù)保存到二級緩存中。