MyBatis 是持久層框架,支持一級緩存和二級緩存
mybatis提供查詢緩存,用於減輕數據壓力,提高數據庫性能。
1. 一級緩存: 基於PerpetualCache 的 HashMap本地緩存,其存儲作用域爲 Session,當 Session flush 或 close 之後,該Session中的所有 Cache 就將清空。
2. 二級緩存與一級緩存其機制相同,默認也是採用 PerpetualCache,HashMap存儲,不同在於其存儲作用域爲 Mapper(Namespace),並且可自定義存儲源,如 Ehcache。
3. 對於緩存數據更新機制,當某一個作用域(一級緩存/二級緩存)的進行了 C/U/D 操作後,默認該作用域下所有 select 中的緩存將被清空。
一級緩存
一級緩存是SqlSession級別的緩存。在操作數據庫時需要構造 sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。
package com.aiit.test;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.aiit.pojo.User;
public class TestMyBatisDemo {
/*
* 一級緩存: 也就Session級的緩存(默認開啓)
*/
public static void main(String[] args) {
String resource="mybatis.cfg.xml";
InputStream inputStream = TestMyBatisDemo.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
//1.查詢
String statement1 = "com.aiit.dao.UserMapper.selectOne";
User user1 = session.selectOne(statement1,1);
System.out.println("查詢結果1: " + user1);
/*
必須是同一個Session,如果session對象已經close()過了就不可能用了
*/
user1 = session.selectOne(statement1,1);
System.out.println("查詢結果2: " + user1);
session.close();
/**
* session被關閉下面代碼就沒有結果,需要重新執行session = factory.openSession();
* user1 = session.selectOne(statement1,1);
System.out.println("查詢結果3: " + user1);
*/
session = factory.openSession();
user1 = session.selectOne(statement1,1);
System.out.println("查詢結果4: " + user1);
//3.修改 執行增刪改時都會自動清除緩存,確保操作後和數據庫一致
String statement3 = "com.aiit.dao.UserMapper.updateOne";
User user3 = new User(9, "中國");
int updateResult = session.update(statement3, user3);
System.out.println("修改成功"+updateResult);
session.commit();
session.close();
}
}
特別注意的地方:
1.一級緩存: 也就Session級的緩存(默認開啓)
2. 必須是同一個Session,如果session對象已經close()過了就不可能用了,需要重新session = factory.openSession();
3.一旦執行增刪改,緩存將會被清除
二級緩存
1.在mybatis.cfg.xml中開啓二級緩存
<configuration>
<settings>
<!--這個配置使全局的映射器(二級緩存)啓用或禁用緩存-->
<setting name="cacheEnabled" value="true" />
.....
</settings>
....
</configuration>
2.UserMapper.xml在映射文件中開啓二級緩存
具體配置 開啓緩存cache、執行緩存useCache、刷新緩存flushCache
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aiit.dao.UserMapper">
<!--開啓本mapper的namespace下的二級緩存-->
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
<!--可以通過設置useCache來規定這個sql是否開啓緩存,ture是開啓,false是關閉-->
<select id="selectOne" parameterType="int" resultType="com.aiit.pojo.User" useCache="true">
SELECT * FROM tbl_user WHERE tbl_user.id=#{id}
</select>
<!--刷新二級緩存 flushCache
<select id="selectOne" parameterType="int" resultType="com.aiit.pojo.User" flushCache="true">
SELECT * FROM tbl_user WHERE tbl_user.id=#{id}
</select>
-->
</mapper>
3.使用二級緩存時,User類必須實現一個Serializable接口===> User implements Serializable
4.測試二級緩存
使用兩個不同的SqlSession對象去執行相同查詢條件的查詢,第二次查詢時不會再發送SQL語句,而是直接從緩存中取出數據
package com.aiit.test;
import java.io.InputStream;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.aiit.pojo.User;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
String resource="mybatis.cfg.xml";
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//開啓兩個不同的SqlSession
SqlSession session1 = factory.openSession();
SqlSession session2 = factory.openSession();
String statement1 = "com.aiit.dao.UserMapper.selectOne";
User user1 = session1.selectOne(statement1,1);
//一定要提交事務之後二級緩存纔會起作用
session1.commit();
System.out.println("查詢結果1: " + user1);
//由於使用的是兩個不同的SqlSession對象,所以即使查詢條件相同,一級緩存也不會開啓使用
user1 = session2.selectOne(statement1,1);
System.out.println("查詢結果1: " + user1);
}
}
5.驗證我們可以根據兩條查詢語句的時間,查看是否執行緩存
long startTime = System.currentTimeMillis(); //獲取開始時間
User user1 = session1.selectOne(statement1,1); //測試的代碼段
long endTime = System.currentTimeMillis(); //獲取結束時間
long time = endTime - startTime ;
System.out.println("查詢時間: " + time );
特別注意:
1. 映射語句文件中的所有select語句將會被緩存。
2. 映射語句文件中的所有insert,update和delete語句會刷新緩存。
3. 緩存會使用Least Recently Used(LRU,最近最少使用的)算法來收回。
4. 緩存會根據指定的時間間隔來刷新。
5. 緩存會存儲1024個對象
cache標籤
<cache
eviction="FIFO" <!--回收策略爲先進先出-->
flushInterval="60000" <!--自動刷新時間60s-->
size="512" <!--最多緩存512個引用對象-->
readOnly="true"/> <!--只讀-->
1.eviction:代表的是緩存回收策略,目前MyBatis提供以下策略。
(1) LRU,最近最少使用的,一處最長時間不用的對象
(2) FIFO,先進先出,按對象進入緩存的順序來移除他們
(3) SOFT,軟引用,移除基於垃圾回收器狀態和軟引用規則的對象
(4) WEAK,弱引用,更積極的移除基於垃圾收集器狀態和弱引用規則的對象。這裏採用的是LRU,移除最長時間不用的對形象
2. flushInterval:刷新間隔時間,單位爲毫秒,這裏配置的是100秒刷新,如果你不配置它,那麼當SQL被執行的時候纔會去刷新緩存。
3.size:引用數目,一個正整數,代表緩存最多可以存儲多少個對象,不宜設置過大。設置過大會導致內存溢出。
4. readOnly:只讀,意味着緩存數據只能讀取而不能修改,這樣設置的好處是我們可以快速讀取緩存,缺點是我們沒有辦法修改緩存,他的默認值是false,不允許我們修改。