一级缓存&二级缓存
一级缓存
目标
- 为什么要缓存
- 一级缓存的使用
缓存概述
为什么要使用缓存
如果每次访问数据库都去获取连接,查询数据库的记录,返回结果集,效率比较低。
缓存相当于服务器内存中一块区域,会缓存最近查询的SQL语句以及sql语句的查询结果,如果再次发送相同的SQL语句,mybatis就不再重新访问数据库,而是从内存中读取已经存在的数据返回给客户端。
使用缓存的目的:就是为了提升查询的速度
缓存的分类
在mybatis中缓存分成2类:
- 一级缓存
- 二缓缓存
缓存结构
- 一级缓存是默认打开的,会话级别缓存,只在一个会话中起作用。
- 二级缓存必须是手动开启,可以在各个会话之间共享数据
案例:一级缓存
一级缓存的范围:只在同一个会话中起作用,默认是自动开启的。
需求
通过同一个 sqlSession 对象,通过id查询2次,观察发出 sql 语句的次数。
步骤
- 在同一个测试方法中查询2次
- 输出用户信息
代码
package com.tyhxzy.test;
import com.tyhxzy.dao.UserMapper;
import com.tyhxzy.entity.User;
import com.tyhxzy.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
/**
* 使用一级缓存
*/
public class TestFirstLevelCache {
public static void main(String[] args) {
//1.获取一个会话对象
SqlSession session = SqlSessionUtils.getSession();
//2.查询2次用户对象
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.findUserById(1);
System.out.println("名字:" + user.getUsername());
//3.第2次执行
User user2 = userMapper.findUserById(1);
System.out.println("名字:" + user2.getUsername());
session.close();
}
}
效果
DEBUG - ==> Preparing: select * from user where id=?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - <== Total: 1
名字:孙悟空
名字:孙悟空
一级缓存的分析
案例:一级缓存的清空
清空的目的:如果进行了增删改的操作,表中的记录有可能发生变化,缓存中的数据就是脏数据。
清空的方式: 只要执行了增删改的操作,提交事务,关闭会话操作会就自动清空一级缓存的数据
需求
- 第一次查询以后,提交会话
- 再进行第二次查询,观察查询结果
代码
package com.tyhxzy.test;
import com.tyhxzy.dao.UserMapper;
import com.tyhxzy.entity.User;
import com.tyhxzy.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
/**
* 使用一级缓存
*/
public class TestFirstLevelCache {
public static void main(String[] args) {
//1.获取一个会话对象
SqlSession session = SqlSessionUtils.getSession();
//2.查询2次用户对象
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.findUserById(1);
System.out.println("名字:" + user.getUsername());
//清除缓存
session.clearCache();
//3.第2次执行
User user2 = userMapper.findUserById(1);
System.out.println("名字:" + user2.getUsername());
session.close();
}
}
效果
DEBUG - ==> Preparing: select * from user where id=?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - <== Total: 1
名字:孙悟空
DEBUG - ==> Preparing: select * from user where id=?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - <== Total: 1
名字:孙悟空
小结
-
什么是一级缓存
在同一个会话中起作用
-
如何清除一级缓存
增删改,提交事务,关闭会话
二级缓存
目标
二级缓存的配置和使用
概述
什么是二级缓存?
范围:在多个会话中起作用,如果有2个会话进行相同查询,就会使用缓存。
步骤
- mybatis-config.xml开启二级缓存
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
- 缓存的实体类要序列化
为什么要序列化?把内存中对象写到硬盘的文件中
因为二级缓存缓存的数据量可能非常大,服务器不会将所有的对象都放在内存中,有些数据放在硬盘的文件中。
public class User implements Serializable
- 创建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="com.tyhxzy.dao.UserMapper">
<!--
开启二级缓存:对当前配置文件中所有的查询进行二级缓存
-->
<cache/>
<select id="findUser" resultType="com.tyhxzy.entity.User">
select * from user where id=#{id}
</select>
</mapper>
<cache>标签作用
- 所有在映射文件里的 select 语句都将被缓存。
- 所有在映射文件里 insert,update 和 delete 语句会清空缓存。
- 缓存使用“最近很少使用”算法来回收
- 每个缓存可以存储 1024 个列表或对象的引用。
- 缓存获取的对象不是共享的且对调用者是安全的,不会有其它的调用者或线程潜在修改。
案例:二级缓存
需求
通过两个 sqlSession 对象,执行两次通过id查询用户,观察发出 sql 语句的次数。
步骤
- 创建一个会话查询1条记录,关闭会话
- 再创建一个会话查询1条记录,关闭会话
- 观察命中的概率
代码
package com.tyhxzy.test;
import com.tyhxzy.dao.UserMapper;
import com.tyhxzy.entity.User;
import com.tyhxzy.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
/**
* 测试二级缓存
*/
public class TestSecondCache {
public static void main(String[] args) {
//创建第一个会话
SqlSession s1 = SqlSessionUtils.getSession();
//得到代理对象
UserMapper userMapper = s1.getMapper(UserMapper.class);
User u1 = userMapper.findUser(1);
System.out.println(u1);
s1.close();
//创建第二个会话
SqlSession s2 = SqlSessionUtils.getSession();
//得到代理对象
UserMapper userMapper2 = s2.getMapper(UserMapper.class);
User u2 = userMapper2.findUser(1);
System.out.println(u2);
s2.close();
}
}
效果
DEBUG - ==> Preparing: select * from user where id=?
DEBUG - ==> Parameters: 1(Integer)
DEBUG - <== Total: 1
User{id=1, username='孙悟空', birthday=1980-10-24, sex='男', address='花果山水帘洞'}
DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2a556333]
DEBUG - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2a556333]
DEBUG - Returned connection 710239027 to pool.
命中率50%
DEBUG - Cache Hit Ratio [com.tyhxzy.dao.UserMapper]: 0.5
User{id=1, username='孙悟空', birthday=1980-10-24, sex='男', address='花果山水帘洞'}
二级缓存分析
- 第1个会话查询完成以后,将查询的结果放在二级缓存中
- 如果有其它的会话进行相同的查询,会直接在二级缓存中读取,不再访问数据库
- 如果有会话执行了增删改,提交事务的方法,就会清空缓存
小结
- 在核心配置文件中开启二级缓存:cacheEnabled=true
- 对缓存实体类序列化
- 在配置文件中开启缓存<cache/>