1. 程式人生 > >Mybatis學習總結五之快取

Mybatis學習總結五之快取

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,不允許我們修改。