Mybatis應用學習(5)——查詢緩存

1. 什麼是查詢緩存

    1. Mybatis提供了查詢緩存的功能,用於減輕數據庫查詢壓力,分別提供了一級緩存和二級緩存兩種緩存級別。java

    2. 查詢緩存,就是將SQL查詢語句查詢的結果緩存中內存中(經過HashMap保存),若是屢次執行同一個查詢語句,就不須要每次都與數據庫進行一次會話(建立SqlSeesion對象發送SQL語句),而是直接從內存中取出查詢的結果,這樣就能夠提升性能,減小數據庫壓力。mysql

    3. 一級緩存是SqlSession級別的緩存。在操做數據庫時須要構造 sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。不一樣的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。spring

    4. 二級緩存是mapper級別的緩存,多個SqlSession去操做同一個Mapper的sql語句,多個SqlSession能夠共用二級緩存,二級緩存是跨SqlSession的。sql

2. 一級緩存

    1. 工做原理:以查詢用戶爲例,數據庫

  • 第一次發起查詢用戶id爲1的用戶信息,先去找緩存中是否有id爲1的用戶信息,若是沒有,從數據庫查詢用戶信息。獲得用戶信息,將用戶信息存儲到一級緩存中。
  • 若是sqlSession去執行commit操做(即執行插入、更新、刪除),清空SqlSession中的一級緩存,這樣作的目的爲了讓緩存中存儲的是最新的信息,避免髒讀。
  • 第二次發起查詢用戶id爲1的用戶信息(SQL語句相同,傳入的參數也相同),先去找緩存中是否有id爲1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。

    2. Mybatis默認開啓一級緩存,因此不須要進行配置操做。apache

    3. 應用:緩存

在正式開發中,是將mybatis和spring進行整合開發,事務控制在service中。
一個service方法中包括 不少mapper方法調用。
service(){
	//開始執行時,開啓事務,建立SqlSession對象
	//第一次調用mapper的方法findUserById(1)
	//第二次調用mapper的方法findUserById(1),從一級緩存中取數據
	//方法結束,sqlSession關閉
}
若是是執行兩次service調用查詢相同 的用戶信息,不走一級緩存,由於session方法結束,sqlSession就關閉,一級緩存就清空。

3. 二級緩存

    1. 工做原理:首先要開啓二級緩存session

  • sqlSession1去查詢用戶id爲1的用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。
  • 若是SqlSession3去執行相同 mapper下sql,執行commit提交,清空該 mapper下的二級緩存區域的數據。
  • sqlSession2去查詢用戶id爲1的用戶信息,去緩存中找是否存在數據,若是存在直接從緩存中取出數據。

    2. 二級緩存與一級緩存區別:二級緩存的範圍更大,多個sqlSession能夠共享一個UserMapper的二級緩存區域;其次二級緩存的位置不必定是內存中,也有多是硬盤或者其餘緩存介質。UserMapper有一個二級緩存區域(按namespace分) ,其它mapper也有本身的二級緩存區域(按namespace分)。每個namespacemapper都有一個二緩存區域,兩個mappernamespace若是相同,這兩個mapper執行sql查詢到數據將存在相同 的二級緩存區域中。數據結構

    3. 配置開啓二級緩存:首先在Mybatis的啓動配置文件SqlMapConfig.xml中加入<setting name="cacheEnabled" value="true"/> ,而後在要開啓二級緩存的Mapper映射文件中添加<cache></cache> 標籤mybatis

<!--啓動配置文件-->
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<settings>
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
<!--開啓二級緩存-->
		<setting name="cacheEnabled" value="true"/>
	</settings>
	<environments default="environment">
		<environment id="environment">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/cloud_note?useUnicode=true&amp;characterEncoding=utf8" />
				<property name="username" value="root" />
				<property name="password" value="123456" />
			</dataSource>
		</environment>
	</environments>
	<!--指定映射文件位置-->
	<mappers>
		<mapper resource="mapper/Usermapper.xml"/>
	</mappers>
</configuration>

<!--Mapper文件配置-->
<?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="dao.UserDao">
<!--開啓二級緩存-->
	<cache></cache>
	<select id="findUserById" parameterType="string" resultType="entity.User">
		select * from cn_user where cn_user_id=#{id}
	</select>
</mapper>

    4. 禁用某SQL查詢語句的二級緩存:在statement中設置useCache=false能夠禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認值是true,即該sql使用二級緩存。<select id="find" resultMap="UserMap" useCache="false">;針對每次查詢都須要最新的數據sql,要設置成useCache=false,禁用二級緩存。

    5. 刷新緩存:在mapper的同一個namespace中,若是有其它insert、update、delete操做數據後須要刷新緩存,若是不執行刷新緩存會出現髒讀。設置statement配置中的flushCache="true" 屬性,默認值爲true即刷新緩存,若是改爲false則不會刷新。使用緩存時若是手動修改數據庫表中的查詢數據會出現髒讀。<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">,通常都應該設置爲true

4. Mybatis與第三方緩存框架整合

    1. Mybatis中的二級緩存不支持分佈式緩存,要實現分佈式緩存須要與第三方緩存工具進行整合使用,經常使用的好比Redis、ehcache等。

    2. 整合原理:mybatis提供了一個Cache接口, 若是要實現本身的緩存邏輯,實現cache接口開發便可。

import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;

public class MyCache implements Cache{
	@Override
	public String getId() {
		return null;
	}
	@Override
	public void putObject(Object key, Object value) {
		
	}
	@Override
	public Object getObject(Object key) {
		return null;
	}
	@Override
	public Object removeObject(Object key) {
		return null;
	}
	@Override
	public void clear() {
	}
	@Override
	public int getSize() {
		return 0;
	}
	@Override
	public ReadWriteLock getReadWriteLock() {
		return null;
	}

}

Mybatis默認使用的Cache實現類(實現二級緩存):使用HashMap實現

package org.apache.ibatis.cache.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

public class PerpetualCache implements Cache {
  private String id;
  private Map<Object, Object> cache = new HashMap<Object, Object>();
  public PerpetualCache(String id) {
    this.id = id;
  }
  public String getId() {
    return id;
  }
  public int getSize() {
    return cache.size();
  }
  public void putObject(Object key, Object value) {
    cache.put(key, value);
  }
  public Object getObject(Object key) {
    return cache.get(key);
  }
  public Object removeObject(Object key) {
    return cache.remove(key);
  }
  public void clear() {
    cache.clear();
  }
  public ReadWriteLock getReadWriteLock() {
    return null;
  }
  public boolean equals(Object o) {
    if (getId() == null) throw new CacheException("Cache instances require an ID.");
    if (this == o) return true;
    if (!(o instanceof Cache)) return false;
    Cache otherCache = (Cache) o;
    return getId().equals(otherCache.getId());
  }
  public int hashCode() {
    if (getId() == null) throw new CacheException("Cache instances require an ID.");
    return getId().hashCode();
  }
}

    除此以外提供了多種緩存策略的實現類:

    3. 配置使用第三方緩存工具:以mybatis和ehcache整合包中提供了一個cache接口的實現類爲例,

  • 首先添加jar包
  • 其次,只須要在Mapper映射文件中的<cache></cache> 標籤中進行配置,經過type屬性來指定當前Mapper的二級緩存使用的Cache實現類,一樣的,若是有本身實現的二級緩存類,也經過type屬性來指定成二級緩存使用的Cache實現類                                                                  

    4. 二級緩存應用場景:對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術下降數據庫訪問量,提升訪問速度,業務場景好比:耗時較高的統計分析sql、電話帳單查詢sql等。由於若是要求查詢結果數據實時性高,那麼仍然會頻繁的與數據進行交互,二級緩存就是去了意義;經過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,好比設置爲30分鐘、60分鐘、24小時等,根據需求而定,在Mapper映射文件中的<cache>標籤指定flushInterval屬性的值便可,如<cache flushInterval="6000"></cache>,單位爲毫秒

相關文章
相關標籤/搜索