05、MyBatis 緩存

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", "[email protected]", "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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章