12.1 一级缓存
12.1.1 缓存概述
用mybatis从数据库中查询数据,如果有多个用户使用同一个SQL语句来查询记录,得到相同的查询结果。
如果表中记录很多,查询速度比较慢。使用缓存的目的就是为了提升查询的速度。缓存是内存中一个区域,保存已经查询过的记录。
12.1.2 缓存分类
- 一级缓存:使用范围是在同一个会话
- 二级缓存:可以在不同的会话中使用
12.1.3 缓存结构
**一级缓存的范围:**在同一个会话中使用
需求实现: 通过同一个 sqlSession 对象,通过id查询2次,观察发出 sql 语句的次数。
12.1.4 测试代码
/**
* 1、在同一个测试方法中查询2次
* 2、输出用户信息
*/
@Test
public void testFirstLevelCache1(){
// 1.打开会话
session = SessionFactoryUtils.getSession();
//2.在同一个会话中查询2次,观察SQL语句生成次数
userMapper = session.getMapper(UserMapper.class);
// 3.得到用户拓展信息
UserInfo userInfo1 = userMapper.findUserInfoById(1);
System.out.println(userInfo1);
// 4.第二次查询: 使用缓存
UserInfo userInfo2 = userMapper.findUserInfoById(1);
System.out.println(userInfo2);
// 5.关闭会话
session.close();
}
12.1.5 执行结果
12.1.6 一级缓存的分析
-
第1次查询记录,将查询到的数据写入到缓存中
-
第2次查询的时候,首先从缓存中去读取数据,如果缓存中有数据,直接返回,而不去访问数据库了。
-
如果这个会话执行了添加,修改,删除,提交,关闭清空当前会话的1级缓存。
12.1.7 一级缓存清空
清空的方式:sqlSession 执行添加、修改、删除、提交、关闭等操作,清空 sqlSession 中的一级缓存数据。
清空的目的:为了让缓存中存放最新数据,避免脏读。
12.1.8 测试代码
/**
* 1、第一次查询以后,提交会话
* 2、再进行第二次查询,观察查询结果
*/
@Test
public void testFirstLevelCache2(){
// 1.打开会话
session = SessionFactoryUtils.getSession();
//2.在同一个会话中查询2次,观察SQL语句生成次数
userMapper = session.getMapper(UserMapper.class);
// 3.得到用户拓展信息
UserInfo userInfo1 = userMapper.findUserInfoById(1);
System.out.println(userInfo1);
session.commit(); // 提交,清空1级缓存
// 第二次查询: 使用缓存
UserInfo userInfo2 = userMapper.findUserInfoById(1);
System.out.println(userInfo2);
}
12.1.9 执行结果
12.2 二级缓存(XML方式)
范围:在不同的会话中起作用
12.2.1 <cache>标签作用
所有在映射文件里的 select 语句都将被缓存。
所有在映射文件里 insert,update 和 delete 语句会清空缓存。
缓存使用“最近很少使用”算法来回收
每个缓存可以存储 1024 个列表或对象的引用。
缓存获取的对象不是共享的且对调用者是安全的,不会有其它的调用者或线程潜在修改。
12.2.2 实体类要序列化
/**
用户扩展信息类
*/
public class UserInfo implements Serializable{
}
12.2.3 编写用户接口
/**
* 查询所有的用户拓展信息
*/
List<UserInfo> findAllUserInfo();
12.2.4 sqlMapConfig.xml
<!--开启二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
12.2.5 创建UserMapper.xml
- 开启二级缓存
- 编写查询语句
<?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="cn.guardwhy.dao.UserMapper">
<!--当前的映射文件中所有的查询操作使用缓存-->
<cache/>
<select id="findAllUserInfo" resultType="userInfo">
select * from user_info
</select>
</mapper>
12.2.6 测试代码
@Test
/**
* 1. 创建一个会话查询1条记录,关闭会话
* 2. 再创建一个会话查询1条记录,关闭会话
*/
public void testFirstLevelCache3(){
// 1.创建第一个会话
SqlSession session1 = SessionFactoryUtils.getSession();
UserMapper userMapper1 = session.getMapper(UserMapper.class);
// 2.得到所有用户拓展信息
List<UserInfo> userInfos1 = userMapper1.findAllUserInfo();
// 2.遍历操作
userInfos1.forEach(System.out::println);
// 3.关闭会话
session1.close();
// 1.创建第一个会话
SqlSession session2 = SessionFactoryUtils.getSession();
UserMapper userMapper2 = session.getMapper(UserMapper.class);
// 2.得到所有用户拓展信息
List<UserInfo> userInfos2 = userMapper2.findAllUserInfo();
// 2.遍历操作
userInfos2.forEach(System.out::println);
// 3.关闭会话
session2.close();
}
12.2.7 执行结果
12.3 二级缓存(注解方式)
只需要在UserMapper接口上使用@CacheNamespace对接口中所有的查询方法使用二级缓存
12.3.1 测试代码
package cn.guardwhy.dao;
import cn.guardwhy.domain.OrderForm;
import cn.guardwhy.domain.User;
import cn.guardwhy.domain.UserInfo;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
/**
* 持久化接口:UserMapper
*/
@CacheNamespace
public interface UserMapper {
/**
* 查询所有的用户拓展信息
*/
@Select("select * from user_info")
List<UserInfo> findAllUserInfo();
}
12.3.2 二级缓存分析