05、MyBatis 快取

Pluto_H發表於2020-06-23

1.MyBatis快取

  MyBatis 包含一個非常強大的查詢快取特性,它可以非常方便地配置和定製.快取可以極大的提升查詢效率.

 

1).一級快取

	public Employee getEmpById(Integer id);

  

	<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql" >
		select * from tbl_employee where id = #{id}
	</select>

  

	@Test
	public void testFirstLevelCache() throws IOException {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			Employee emp01 = mapper.getEmpById(10);
			System.out.println(emp01);
			
			//
			Employee emp02 = mapper.getEmpById(1-0);
			System.out.println(emp02);
			System.out.println(emp01==emp02);
			
		}finally {
			openSession.close();
		}
	}

2).一級快取失效情況

(1).sqlSession不同

(2).sqlSession相同,查詢條件不同(當前一級快取中還沒有這個資料)

(3).sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前資料有影響)

(4).sqlSession相同,手動清除了一級快取

	public Employee getEmpById(Integer id);

  

	<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql" >
		select * from tbl_employee where id = #{id}
	</select>

  

	@Test
	public void testFirstLevelCache() throws IOException {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			Employee emp01 = mapper.getEmpById(10);
			System.out.println(emp01);
			
			//1、Sqlsession不同
//			SqlSession openSession2 = sqlSessionFactory.openSession();
//			EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
//			Employee emp02 = mapper2.getEmpById(10);
			
			//2、sqlSession相同,查詢條件不同
//			Employee emp02 = mapper.getEmpById(3);
//			System.out.println(emp02);
//			System.out.println(emp01==emp02);
			
			//3、sqlSession相同,兩次查詢之間執行了增刪改操作
//			mapper.addEmp(new Employee(null, "testCache", "cache@cache.com", "1"));
//			System.out.println("資料新增成功");
//			Employee emp02 = mapper.getEmpById(10);
//			System.out.println(emp02);
//			System.out.println(emp01==emp02);
			
			//4、sqlSession相同,手動清除了一級快取
			openSession.clearCache();
			Employee emp02 = mapper.getEmpById(10);
			System.out.println(emp02);
			System.out.println(emp01==emp02);
			
		}finally {
			openSession.close();
		}
	}

  

3).二級快取

  二級快取(second level cache),全域性作用域快取.

  二級快取預設不開啟,需要手動配置.

  MyBatis提供二級快取的介面以及實現,快取實現要求POJO實現Serializable介面.

  二級快取在 SqlSession 關閉或提交之後才會生效.

(1).二級快取使用

二級快取使用:

①.開啟全域性二級快取配置:<setting name="cacheEnabled" value="true"/>

②.去需要使用二級快取的xml中配置使用二級快取;新增<cache></cache>

③.POJO需要實現序列化介面

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

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
	<!-- cache:使用二級快取的namespace -->
	<!-- eviction:快取的清除策略;LRU|FIFO|SOFT|WEAK -->
		<!-- LRU – 最近最少使用的:移除最長時間不被使用的物件。 -->
		<!-- FIFO – 先進先出:按物件進入快取的順序來移除它們。 -->
		<!-- SOFT – 軟引用:基於垃圾回收器狀態和軟引用規則移除物件。 -->
		<!-- WEAK – 弱引用:更積極地基於垃圾收集器狀態和弱引用規則移除物件。 -->
	<!-- flushInterval(重新整理間隔):快取多長時間清空一次,預設不清空,可以設定一個毫秒值啟用重新整理間隔 -->
	<!-- readOnly(只讀):屬性可以被設定為 true 或 false -->
		<!-- true:只讀;mybatis認為所有從快取中獲取資料的操作都是隻讀操作,不會修改資料; -->
			<!-- 只讀的快取會給所有呼叫者返回快取物件的相同例項。 因此這些物件不能被修改。 提供了可觀的效能提升-->
		<!-- false:非只讀;mybatis覺得獲取的資料可能會被修改; -->
			<!-- 可讀寫的快取會(通過序列化)返回快取物件的拷貝。 速度上會慢一些,但是更安全,因此預設值是 false -->
	<!-- size(引用數目):屬性可以被設定為任意正整數,要注意欲快取物件的大小和執行環境中可用的記憶體資源.預設值是 1024 -->
	<!-- type:屬性指定的類必須實現 org.apache.ibatis.cache.Cache 介面.且提供一個接受 String 引數作為 id 的構造器 -->
		<!-- 指定自定義快取的全類名,實現Cache介面即可 -->
	<!-- <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> -->
	<cache></cache>
</mapper>

  

	@Test
	public void testSecondLevelCache() throws IOException {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		SqlSession openSession2 = sqlSessionFactory.openSession();
		try {
			//1、
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
			
			Employee emp01 = mapper.getEmpById(1);
			System.out.println(emp01);
			openSession.close();
			
			//第二次查詢是從二級快取中拿到的資料,並沒有傳送新的sql
			//mapper2.addEmp(new Employee(null, "aaa", "nnn", "0"));
			Employee emp02 = mapper2.getEmpById(1);
			System.out.println(emp02);
			openSession2.close();
		}finally {
			
		}
	}

  

(2).二級快取工作原理

二級快取工作原理:

①.一個會話,查詢一條數,這個資料就會被放在當前會話的一級快取中;

②.如果會話關閉;一級快取中的資料會被儲存到二級快取中;新的會話查詢資訊,就可以參照二級快取中的內容;

③.不同namespace查出的資料會放在自己對應的快取中(map):sqlSession===EmployeeMapper==>Employee|DepartmentMapper===>Department

④.二級快取工作效果:查出的資料都會被預設先放在一級快取中.只有會話提交或者關閉以後,一級快取中的資料才會轉移到二級快取中;

 

(3).二級快取屬性設定

①.cacheEnabled="true|false": false關閉快取(二級快取關閉)(一級快取一直可用的)

②.每個select標籤都有useCache="true|false": false不使用快取(一級快取依然使用,二級快取不使用)

③.*每個增刪改標籤的:flushCache="true|false":(一級二級都會清除)增刪改執行完成後就會清楚快取;

測試:flushCache="true":一級快取會被清空;二級也會被清空;每次查詢之後都會清空快取,快取是沒有被使用的;

④.sqlSession.clearCache();只是清除當前session的一級快取

⑤.localCacheScope:本地快取作用域;一級快取SESSION;當前會話的所有資料儲存在會話快取中;STATEMENT:可以禁用一級快取;

/**

* MyBatis系統中預設定義了兩級快取:一級快取和二級快取

* 一級快取(本地快取):sqlSession級別的快取;一級快取是一直開啟的;SqlSession級別的一個Map

* 與資料庫同一次會話期間查詢到的資料會放在本地快取中;

* 以後如果需要獲取相同的資料,直接從快取中拿,沒必要再去查詢資料庫;

* 一級快取失效情況:沒有使用到一級快取的情況,效果就是兩次查詢都需要向資料庫發出查詢

* 1sqlSession不同

* 2sqlSession相同,查詢條件不同(當前一級快取中還沒有這個資料)

* 3sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前資料有影響)

* 4sqlSession相同,手動清除了一級快取

*

* 二級快取(全域性快取):基於namespace級別的快取;一個namespace對應一個二級快取;

* 二級快取工作原理:

* 1、一個會話,查詢一條數,這個資料就會被放在當前會話的一級快取中;

* 2、如果會話關閉;一級快取中的資料會被儲存到二級快取中;新的會話查詢資訊,就可以參照二級快取中的內容;

* 3、不同namespace查出的資料會放在自己對應的快取中(map):sqlSession===EmployeeMapper==>Employee|DepartmentMapper===>Department

* 二級快取工作效果:查出的資料都會被預設先放在一級快取中.只有會話提交或者關閉以後,一級快取中的資料才會轉移到二級快取中;

* 二級快取使用:

* 1、開啟全域性二級快取配置:<setting name="cacheEnabled" value="true"/>

* 2、去需要使用二級快取的xml中配置使用二級快取;新增<cache></cache>

* 3POJO需要實現序列化介面

*

* 快取有關屬性/設定:

* 1cacheEnabled="true|false": false關閉快取(二級快取關閉)(一級快取一直可用的)

* 2、每個select標籤都有useCache="true|false": false不使用快取(一級快取依然使用,二級快取不使用)

* 3*每個增刪改標籤的:flushCache="true|false":(一級二級都會清除)增刪改執行完成後就會清楚快取;

* 測試:flushCache="true":一級快取會被清空;二級也會被清空;每次查詢之後都會清空快取,快取是沒有被使用的;

* 4sqlSession.clearCache();只是清除當前session的一級快取

* 5localCacheScope:本地快取作用域;一級快取SESSION;當前會話的所有資料儲存在會話快取中;STATEMENT:可以禁用一級快取;

* @throws IOException

*/

2.第三方快取整合

  EhCache 是一個純Java的程式內快取框架,具有快速、精幹等特點,是Hibernate中預設的CacheProvider.

  MyBatis定義了Cache介面方便我們進行自定義擴充套件. 

參考文件:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

http://mybatis.org/ehcache-cache/index.html

相關文章