Mybatis一级缓存和二级缓存(带测试方法)
目录
相关导读
一、什么是缓存
二、Mabtis一级缓存
(1)测试一级缓存
(2)清空一级缓存
三、Mybatis二级缓存
(1)开启二级缓存
(2)测试二级缓存
相关导读
Mybatis专栏:
Mybatis系列专栏 | MyBatis入门配置 |
Mybatis入门案例【超详细】 | |
MyBatis配置文件 —— 相关标签详解 | |
Mybatis模糊查询——三种定义参数方法和聚合查询、主键回填 | |
Mybatis动态SQL查询 --(附实战案例--8888个字--88质量分) | |
Mybatis分页查询——四种传参方式 | |
Mybatis一级缓存和二级缓存(带测试方法) | |
Mybatis分解式查询 | |
Mybatis关联查询【附实战案例】 | |
MyBatis注解开发---实现增删查改和动态SQL | |
MyBatis注解开发---实现自定义映射关系和关联查询 |
一、什么是缓存
缓存是内存当中一块存储数据的区域,目的是提高查询效率。MyBatis会将查询结果存储在缓存当中,当下次执行相同的SQL时不访问数据库,而是直接从缓存中获取结果,从而减少服务器的压力。
什么是缓存?
存在于内存中的一块数据。
缓存有什么作用?
减少程序和数据库的交互,提高查询效率,降低服务器和数据库的压力。
什么样的数据使用缓存?
经常查询但不常改变的,改变后对结果影响不大的数据。
MyBatis缓存分为哪几类?
一级缓存和二级缓存
如何判断两次Sql是相同的?
- 查询的Sql语句相同
- 传递的参数值相同
- 对结果集的要求相同
- 预编译的模板Id相同
二、Mabtis一级缓存
MyBatis一级缓存也叫本地缓存。SqlSession对象中包含一个Executor对象,Executor对象中包含一个PerpetualCache对象,在该对象存放一级缓存数据。
由于一级缓存是在SqlSession对象中,所以只有使用同一个SqlSession对象操作数据库时才能共享一级缓存。
MyBatis的一级缓存是默认开启的,不需要任何的配置。
如下图所示:
(1)测试一级缓存
其实测试方法很简单,就是通过使用相同和不同的SqlSession对象进行SQL查询,返回的对象的哈希值是否一样就可以知道了,如果返回的哈希值一样说明没有进行SQL查询,而是直接从缓存拿到对象来返回
下面是使用相同的Session对象来执行查询,如果观察user1和user2的哈希值一样则说明确实开启了一级缓存,并没有进行查询,而是直接从缓存中拿数据。
import com.mybatisstudy.mapper.UserMapper;
import com.mybatisstudy.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import java.io.InputStream;public class TestUserMapper3 {// 测试使用同一个SqlSession查询@Testpublic void testCache1() throws Exception{InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(is);SqlSession session = factory.openSession();// 使用同一个SqlSession查询UserMapper mapper1 = session.getMapper(UserMapper.class);UserMapper mapper2 = session.getMapper(UserMapper.class);User user1 = mapper1.findById(1);System.out.println(user1.hashCode());System.out.println("------------------------------------------");User user2 = mapper2.findById(1);System.out.println(user2.hashCode());session.close();}
}
执行结果
OK,确实返回的哈希值都是一样的,并且我们可以通过控制台输出显示它并没有进行查询而是直接从缓存中拿到对象并返回,所以这就是一级缓存 ,提高了查询效率。
下面使用不同的SqlSession来进行测试一下,返回的哈希值是否一致
// 测试使用不同SqlSession查询@Testpublic void testCache2() throws Exception{InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(is);SqlSession session1 = factory.openSession();SqlSession session2 = factory.openSession();// 测试使用不同SqlSession查询UserMapper mapper1 = session1.getMapper(UserMapper.class);UserMapper mapper2 = session2.getMapper(UserMapper.class);User user1 = mapper1.findById(1);System.out.println(user1.hashCode());System.out.println("---------------------------------");User user2 = mapper2.findById(1);System.out.println(user2.hashCode());session1.close();session2.close();}
运行结果
OK,可以看到,返回的哈希值不一样,并且从控制台输出显示也可以看到这里的确也进行了一次查询,因此可以证实,共享一级缓存确实是基于SqlSession对象的
(2)清空一级缓存
但是吧,如果缓存过多的话,也是会影响我们的查询效率的,所以这时候就需要清空缓存了,就像我们时不时要清理一下手机缓存否则就会很卡,是同样的道理,那怎么清空一级缓存呢?
进行以下操作可以清空MyBatis一级缓存:
- SqlSession 调用 close() :操作后SqlSession对象不可用,该对象的缓存数据也不可用。
- SqlSession 调用 clearCache() / commit() :操作会清空一级缓存数据。
- SqlSession 调用增删改方法:操作会清空一级缓存数据,因为增删改后数据库发生改变,缓存数据将不准确
// 清空Mybatis一级缓存@Testpublic void testCache3() throws Exception{InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(is);SqlSession session = factory.openSession();UserMapper mapper1 = session.getMapper(UserMapper.class);UserMapper mapper2 = session.getMapper(UserMapper.class);User user1 = mapper1.findById(1);System.out.println(user1.hashCode());// 清空Mybatis一级缓存session.clearCache();System.out.println("-------------------------------");User user2 = mapper2.findById(1);System.out.println(user2.hashCode());session.close();}
执行效果
OK,返回的哈希值也确实不一样, 但是我们有没有观察到这和上面使用不同的SqlSession对象来执行查询的时候,控制台输入显示有点不一样,那就是这里不用再建立JDBC连接,也有效了提高查询效率,所以我们偶尔还是要清空一下缓存才行
三、Mybatis二级缓存
- MyBatis二级缓存也叫全局缓存。数据存放在SqlSessionFactory中,只要是同一个工厂对象创建的SqlSession,在进行查询时都能共享数据。一般在项目中只有一个SqlSessionFactory对象,所以二级缓存的数据是全项目共享的。
- MyBatis一级缓存存放的是对象,二级缓存存放的是对象的数据。所以要求二级缓存存放的POJO必须是可序列化的,也就是要实现Serializable接口。
- MyBatis二级缓存默认不开启,手动开启后数据先存放在一级缓存中,只有一级缓存数据清空后,数据才会存到二级缓存中。
- SqlSession 调用 clearCache() 无法将数据存到二级缓存中。
(1)开启二级缓存
1. POJO类实现Serializable接口
import java.io.Serializable;public class User implements Serializable {private int id;private String username;private String sex;private String address;
}
2. 在Mybatis配置文件添加如下设置
<!-- 二级缓存打开 --> <settings><setting name="cacheEnabled" value="true"/> </settings>
这里有个额外知识,就是Mybatis配置文件的标签还得按照顺序来放的,否则就会以下编译错误;
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
databaseIdProvider?,mappers?)".
同时也说明了放置顺序就得按照match里面的顺序来放
3. 添加 <cache /> 标签
如果查询到的集合中对象过多,二级缓存只能缓存1024个对象引用。可以通过
<cache /> 标签的size属性修改该数量。
比如:<cache size="2048"/>
(2)测试二级缓存
那怎么测试呢,从上面我们可以知道二级缓存存放的是对象的数据,并且是基于SqlSessionFactory的,因此我们可以用SqlSessionFactory获取两个SqlSession对象,然后让他们分别获取各自的mapper,然后进行查询,返回到同一个实例化的USer对象中,如果返回的数据是一致的,但是对象的哈希值是不一样的话,则说明二级缓存里存放的确实对象的数据而不是对象。
// 测试二级缓存 @Test public void testCache4() throws Exception {InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(is);SqlSession session = factory.openSession();UserMapper mapper1 = session.getMapper(UserMapper.class);UserMapper mapper2 = session.getMapper(UserMapper.class);User user1 = mapper1.findById(1);System.out.println(user1);System.out.println(user1.hashCode());// 让一级缓存失效session.commit();System.out.println("----------------------------");user1 = mapper2.findById(1);System.out.println(user1);System.out.println(user1.hashCode()); }
运行结果
OK,从运行结果上我们可以知道结果集返回到同一个对象中,而他们的哈希值反而不一样,说明执行第二次查询的时候新建了一个对象并且该对象指向那个对象并且将SqlSessionFactory中的数据赋值到新建的那个对象。其实从控制台打印的日志我们也可以得出,并没有执行查询方法,因为没有打印SQL语句,而且缓存也是从0.0改成了0.5,因此我们可以断定二级缓存存放的是数据而不是对象。
Mybatis一级缓存和二级缓存(带测试方法)相关推荐
- MyBatis框架:延迟加载策策略、一级缓存、二级缓存
MyBatis框架:延迟加载策略和缓存 Mybatis 延迟加载策略 1.1 何为延迟加载? 1.2 实现需求 1.3 使用association实现延迟加载 1.3.1 账户的持久层DAO接口 1. ...
- MyBatis】MyBatis一级缓存和二级缓存
转载自 MyBatis]MyBatis一级缓存和二级缓存 MyBatis自带的缓存有一级缓存和二级缓存 一级缓存 Mybatis的一级缓存是指Session缓存.一级缓存的作用域默认是一个SqlSe ...
- Mybatis源码分析之(七)Mybatis一级缓存和二级缓存的实现
文章目录 一级缓存 二级缓存 总结 对于一名程序员,缓存真的很重要,而且缓存真的是老生常谈的一个话题拉.因为它在我们的开发过程中真的是无处不在.今天LZ带大家来看一下.Mybatis是怎么实现一级缓存 ...
- mybatis 详解------ 一级缓存、二级缓存(九)
mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解: ①.一级缓存是SqlSession级别的缓存.在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMa ...
- MyBatis一级缓存和二级缓存
MyBatis自带的缓存有一级缓存和二级缓存 一级缓存 Mybatis的一级缓存是指Session缓存.一级缓存的作用域默认是一个SqlSession.Mybatis默认开启一级缓存. 也就是在同一个 ...
- Mybatis一级缓存,二级缓存的实现就是这么简单
介绍 又到了一年面试季,所以打算写一点面试常问的东西,争取说的通俗易懂.面试高级岗,如果你说熟悉Mybatis,下面这些问题基本上都会问 Mybatis插件的实现原理? 如何写一个分页插件? Myba ...
- mybatis高级(3)_延迟加载_深度延迟_一级缓存_二级缓存
设置延迟加载需要在mybatis.xml中设置 注: 侵入式延迟加载为真时是延迟加载 侵入式延迟加载为假时是深度延迟加载 <!-- 延迟加载和深度延迟加载 --><settings& ...
- 浅谈Mybatis的一级缓存和二级缓存
MyBatis的缓存机制 缓存的引入 当我们大量执行重复的查询SQL语句的时候,会频繁的和数据库进行通信,会增加查询时间等影响用户体验的问题,可以通过缓存,以降低网络流量,使网站加载速度更快. MyB ...
- Mybatis 详解--- 一级缓存、二级缓存
2019独角兽企业重金招聘Python工程师标准>>> Mybatis 为我们提供了一级缓存和二级缓存,可以通过下图来理解: ①.一级缓存是SqlSession级别的缓存.在操作数据 ...
最新文章
- BeanUtils威力和代价
- 联想打字必须按FN+数字-fn打字
- php怎么看回调的异步通知的数据_php app支付宝回调(异步通知)详解
- NHibernate自定义集合类型(上):基本实现方式
- 爬虫cookie过期_python instagram 爬虫
- android自动生成cardview,学习使用Material Design控件(三)使用CardView实现卡片效果...
- html5 canvas 图像预览,html5-canvas 加载并显示图像
- 信息学奥赛C++语言:旗手
- mysql create database to_mysql之CREATE DATABASE Syntax(创建数据库)
- Python自动获取Redi缓存验证码
- VB根据窗口标题获取应用程序完整路径
- ubuntu20.04 安装 Qt5.12步骤
- asp.net连接access数据库两种方法
- 解决Promise.all一个被rejected,整个都被rejected的缺陷
- 邮箱的正确格式是什么,如何发送一封规范的邮件
- ios html5键盘弹出视图上移,ios 软键盘弹出, 页面整体上移问题
- 全新剪映专业版140内测版!等你体验!
- 会议室预约系统 会议预约 会议预约触摸屏 会议预约管理系统
- 十分透彻:电容去耦原理
- 走进C++程序世界-----指针(动态申请空间和释放空间)