Mybatis应用学习(5)——查询缓存

本文详细解析了MyBatis的一级缓存和二级缓存机制,包括它们的工作原理、配置方法及应用场景,帮助开发者有效提升数据库查询效率。

1. 什么是查询缓存

    1. Mybatis提供了查询缓存的功能,用于减轻数据库查询压力,分别提供了一级缓存和二级缓存两种缓存级别。

    2. 查询缓存,就是将SQL查询语句查询的结果缓存中内存中(通过HashMap保存),如果多次执行同一个查询语句,就不需要每次都与数据库进行一次会话(创建SqlSeesion对象发送SQL语句),而是直接从内存中取出查询的结果,这样就可以提高性能,减少数据库压力。011c7c85b6045f478a27f1491fc28d285f8.jpg

    3. 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

    4. 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

2. 一级缓存

    1. 工作原理:以查询用户为例,

  • 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
  • 如果sqlSession去执行commit操作(即执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
  • 第二次发起查询用户id为1的用户信息(SQL语句相同,传入的参数也相同),先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

    2. Mybatis默认开启一级缓存,所以不需要进行配置操作。

    3. 应用:

在正式开发中,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。
service(){
	//开始执行时,开启事务,创建SqlSession对象
	//第一次调用mapper的方法findUserById(1)
	//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
	//方法结束,sqlSession关闭
}
如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。

3. 二级缓存

    1. 工作原理:首先要开启二级缓存

  • sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
  • 如果SqlSession3去执行相同 mapper下sql,执行commit提交,清空该 mapper下的二级缓存区域的数据。
  • sqlSession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

    2. 二级缓存与一级缓存区别:二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域;其次二级缓存的位置不一定是内存中,也有可能是硬盘或者其他缓存介质。UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespacemapper都有一个二缓存区域,两个mappernamespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。

6de7b9d3fdbbbd1c9c3671ee4cf2456cee5.jpg

    3. 配置开启二级缓存:首先在Mybatis的启动配置文件SqlMapConfig.xml中加入<setting name="cacheEnabled" value="true"/> ,然后在要开启二级缓存的Mapper映射文件中添加<cache></cache> 标签

<!--启动配置文件-->
<?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();
  }
}

    除此之外提供了多种缓存策略的实现类:

7dff7bf3b86c4ff958e3c0511306b3e7184.jpg

    3. 配置使用第三方缓存工具:以mybatis和ehcache整合包中提供了一个cache接口的实现类为例,

  • 首先添加jar包4f43fe9cc25c7264bee8e2a9a8b327f80b3.jpg
  • 其次,只需要在Mapper映射文件中的<cache></cache> 标签中进行配置,通过type属性来指定当前Mapper的二级缓存使用的Cache实现类,同样的,如果有自己实现的二级缓存类,也通过type属性来指定成二级缓存使用的Cache实现类                                                                  41b9ca53c847e6e9fae274ac4b11b13a123.jpg

    4. 二级缓存应用场景:对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。因为如果要求查询结果数据实时性高,那么仍然会频繁的与数据进行交互,二级缓存就是去了意义;通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定,在Mapper映射文件中的<cache>标签指定flushInterval属性的值即可,如<cache flushInterval="6000"></cache>,单位为毫秒

转载于:https://my.oschina.net/ProgramerLife/blog/2962004

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值