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>,单位为毫秒

相关文章
相关标签/搜索