【MyBatis】缓存——使查询变得快快快!
目录
走近科学之——缓存
什么是缓存
Java的缓冲流
字节输入流(InputStream)——子类BufferedInputStream
字节输出流(OutputStream)——子类BufferedOutputStream
MyBatis缓存
特点&缺点
术语&功能
使用场景
适合使用缓存
不适合使用缓存
缓存的分类
一级缓存
配置
工作流程
命中
未命中
案例
一级缓存失效的情况
二级缓存
配置
通过映射器
通过注解
案例
运行结果
POJO类(实现类)序列化问题
二级缓存的位置
一级缓存和二级缓存的对比
二级缓存的特点与缺陷
自定义缓存
走近科学之——缓存
什么是缓存
缓存是CPU的一部分,它存在于CPU中。CPU存取数据的速度非常的快,一秒钟能够存取、处理十亿条指令和数据,而内存就慢很多,快的内存能够达到几十兆就不错了,可见两者的速度差异是多么的大。
缓存是为了解决CPU速度和内存速度的速度差异问题 。内存中被CPU访问最频繁的数据和指令被复制入CPU中的缓存,这样CPU就可以不经常到象“蜗牛”一样慢的内存中去取数据了,CPU只要到缓存中去取就行了,而缓存的速度要比内存快很多。
Java的缓冲流
创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
字节输入流(InputStream)——子类BufferedInputStream
- 底层会创建一个长度是8192的byte数组(缓冲区)
- 每次读取数据存入该缓冲区中
- 减少了读取的次数,提高读取效率
字节输出流(OutputStream)——子类BufferedOutputStream
- 底层会创建一个长度是8192的byte数组(缓冲区)
- 每次写出数据先写到该缓冲区中
- 减少了写出的次数,提高写出效率
MyBatis缓存
缓存(cache),数据交换的缓冲区,当应用程序需要读取数据时,先从数据库中将数据取出,放置在缓冲区中,应用程序从缓冲区读取数据。
类比于上文提到过的缓冲流,MyBatis的缓存属于输出型缓存。
特点&缺点
数据库去除的数据保存在内存中,具备快速读取和使用的特点。
读取数据时无需再从数据库中获取,因此得到的数据可能不是最新的。
术语&功能
命中:当在缓存中找到需要的数据,则直接取出使用。
未命中:当在缓存中未找到需要的数据,则先从数据库中取出并先放入缓冲区,亦方便下次使用。
减少Java项目与数据库的交互次数,从而提升程序的运行效率。
一般通过配置或定制的方式来使用缓存。
使用场景
适合使用缓存
经常查询并且不经常改变,或者数据的正确与否对最终结果影响不大的。
比如:公司的介绍或者新闻。
新闻一般为已经发生且无法改变的事,查询的人会很多,使用缓存可以大大提高效率。
不适合使用缓存
经常改变的数据,或者数据的正确与否对最终结果影响很大的。
比如:商品的库存,股市等等。
由于缓存的缺点,得到的数据可能不是最新的,当商品的库存无法实时更新,不仅会对商家造成损失,也会加大与消费者的纠纷;股市数据一旦不是最新的,股民公司都会得到损失,轻则亏本,重则倾家荡产。
缓存的分类
一级缓存 | 会话Session级别的缓存,针对一次会话操作内 |
二级缓存 | 映射器级别的缓存,针对不同Namespace的映射器 |
自定义缓存 | 根据各类不同的缓存机制,自定义缓存的实现方式 |
一级缓存
一级缓存针对的是SqlSession,是默认开启的,在主配置文件中进行配置。每个Session都有自己的缓存。
配置
我们需要在<configuration>的子标签<settings>中完成对一级缓存的配置,由于一级缓存是默认开启的,因此一般我们不会去手动书写。
value属性有两个值。
SESSION | session级别的缓存 |
STATEMENT | statement级别的缓存 |
因此,当我们需要改变一级缓存级别时再进行修改。
工作流程
命中
未命中
案例
查询学号为33的学生。
- DaoUtil.java——封装SqlSession的基本操作。
public class DaoUtil {private static SqlSessionFactory build;static {try {//读取配置文件//要返回一个流InputStream readConfig = Resources.getResourceAsStream("mybatis-config.xml");//获取工厂对象build = new SqlSessionFactoryBuilder().build(readConfig);} catch (IOException e) {e.printStackTrace();}}public static SqlSession getSqlSession() {return build.openSession();}public static void closeResource(SqlSession ss) {ss.close();}
}
- StudentMapper.java——定义查询方法
@Select("select * from student where sid = #{v}")public Student findStuBySid(int sid);
- StudentTest.java——测试
public class StudentTest {public static void main(String[] args) {SqlSession ss = DaoUtil.getSqlSession();StudentMapper mapper = ss.getMapper(StudentMapper.class);//第一次查询Student stu1 = mapper.findStuBySid(33);System.out.println(stu1);//第二次查询Student stu2 = mapper.findStuBySid(33);System.out.println(stu2);System.out.println(stu1 == stu2);DaoUtil.closeResource(ss);}
}
因此我们也可以知道——打开一个SqlSession会完成两件事:
- 获得SqlSession
- 获得缓冲空间
一级缓存失效的情况
#1. 不同SqlSession对应不同的一级缓存
#2. 同一个SqlSession但查询条件不同
#3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
当同一个SqlSession多次发出相同的SQL语句查询时,MyBatis会直接从缓存中取数据。如果前后两次中间出现过commit操作(修改、添加、删除),则认为数据发生了变化,MyBatis会把SqlSession中的一级缓存区域全部清空,则下一次的SQL语句查询时,需从数据库中查询数据并将查询的结果写入缓存。
#4. 同一个SqlSession两次查询期间手动清空了缓存
SqlSession对象.clearCache()方法。
二级缓存
在使用一级缓存的时候,我们发现:不同SqlSession对应不同的一级缓存,意味着即使我们想查询的为同一的数据,但是使用了不同的SqlSession,仍需不断的访问数据库。
因此,升级版的缓存出现了——二级缓存。
二级缓存是跨SqlSession的缓存,Mapper级别的缓存,面向的是工厂,同一工厂使用一个缓存空间。在Mapper级别的缓存内,不同的SQLSession缓存可以共享。
配置
通过映射器
#1. 在主配置文件中进行配置
<configuration>子标签<settings>。
#2. 在映射文件中进行配置
<mapper>子标签<cache>。
#3. 在使用的操作中配置(在select标签中配置)
通过注解
#1. 在主配置文件中进行配置
<configuration>子标签<settings>。
#2. 用@CacheNamespace注解修饰定义的接口,并将参数blocking设置为true
案例
使用两个SqlSession查询同一学号的学生。
public class CacheTest {public static void main(String[] args) {//第一次查询SqlSession ss1 = DaoUtil.getSqlSession();StudentMapper mapper1 = ss1.getMapper(StudentMapper.class);Student stu1 = mapper1.findStuBySid(33);System.out.println(stu1);//第二次查询SqlSession ss2 = DaoUtil.getSqlSession();StudentMapper mapper2 = ss2.getMapper(StudentMapper.class);Student stu2 = mapper2.findStuBySid(33);System.out.println(stu2);System.out.println(stu1 == stu2);DaoUtil.closeResource(ss2);DaoUtil.closeResource(ss1);}
}
我们发现代码报错了,原因是我们没有对实体类:Student进行序列化。
运行结果
第二次查询不需要获取链接。
POJO类(实现类)序列化问题
1、序列化就是一种用来处理对象流的机制,所谓对象流就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可以在网络之间传输,需要实现Serializable接口,该接口没有需要实现的方法,只是为了表示对象是可以序列化的。序列化是将对象转换为容易传输的格式的过程。
2、是对象永久化的一种机制,在程序终止后,这些对象仍然存在,可以在程序再次启动之后读取这些对象的值,也可以在其他程序利用这些保存下来的值。
3、只有序列化的对象才可以存储在存储设备上。
二级缓存的位置
二级缓存不将数据放入内存,而是序列化到磁盘上。
二级缓存面向的是工厂,使用工厂的好处:节约链接,使得独缺无法造成很多锁竞争,实现真正的节约资源。
一级缓存和二级缓存的对比
缓存 | 面向 | 位置 | 开启方式 | 消亡 |
一级缓存 | SqlSession | 内存 | 自动开启 | 四种失效情况 |
二级缓存 | SqlSessionFactory | 磁盘 | 手动开启 | 随工厂消亡 |
二级缓存的特点与缺陷
当我们使用数据库时,创建表需要遵循三大范式(确保表中每列的原子性、确保表中每列都和主键相关且未直接相关),因此我们通常需要创建多张表。而在实际情况中,一个数据库处理不过来数据时,我们甚至需要一起使用多个数据库——数据库的集群。
相应的,应用/服务器也会集群,比如不同地区的人会访问不同的服务器(英雄联盟分国服、韩服等等……)。
但是,在实际的项目中是绝对不会使用二级缓存的。
每个服务器作为一个工厂——不同工厂无法同步。
自定义缓存
【MyBatis】缓存——使查询变得快快快!相关推荐
- 为什么索引可以让查询变快,你有思考过吗?
作者 | topEngineerray 来源 | https://blog.csdn.net/topdeveloperr/article/details/88742503 概述 人类存储信息的发展历程 ...
- 为什么索引可以让查询变快
Table of Contents 概述 计算机存储原理 索引是如何工作的? 二分查找法 索引为何使得查询变快? 为什么索引不能建立的太多? 索引有弊端吗? 概述 人类存储信息的发展历程大致经历如下: ...
- mybatis中的查询缓存
转载自:https://www.cnblogs.com/zhangzongle/p/6211285.html 查询缓存 Mybatis提供查询缓存,用于减轻数据压力,提高数据库压力. Mybatis提 ...
- Mybatis高级应用 查询缓存
mybatis提供了查询缓存功能,用于减轻数据压力,提高数据库性能.mybatis提供了一级缓存和二级缓存,如下图所示: 从上图可以看出: 一级缓存是存在于一个sqlSession中的,而sqlSes ...
- @Transactional注解和Mybatis缓存问题(Mybatis 查询结果 List 对List修改后再次查询,结果与数据库不一致)
Mybatis 查询结果 List 对List修改后再次查询,结果与数据库不一致 使用 Mybatis 查询,结果为对象的 List ,修改List内的参数后,使用相同参数再次查询,发现查询结果与数据 ...
- Mybatis延迟加载和查询缓存
一.延迟加载 resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 延迟加载:先 ...
- 【转】MyBatis缓存机制
转载:https://blog.csdn.net/bjweimengshu/article/details/79988252. 本文转载自公众号 美团技术点评 前言 MyBatis是常见的Java数据 ...
- redis的基本操作And数据持久化方式以及redis实现mybatis缓存
Redis 1.NoSql # NoSql(Not Only Sql),不仅仅是sql,泛指非关系型数据库 2.NoSql的诞生 随着互联网web2.0网站的兴起,传统的关系型数据库在高并发和特大规模 ...
- MyBatis缓存(一级缓存、二级缓存)
建议直接阅读原文: 聊聊MyBatis缓存机制 - 美团技术团队本文主要从源码角度理解Java ORM框架MyBatis缓存特性.https://tech.meituan.com/2018/01/19 ...
最新文章
- python 生成器 迭代器 yiled
- 阿里小邮局黑科技 这就是传说中“别人的公司”
- LeetCode Copy List with Random Pointer
- ORACLE DBA的职责
- Python实现PLA(感知机)
- amazon 使用密码登录_我们通过使用Amazon SageMaker大规模提供机器学习模型学到了什么...
- Libnet核心数据结构
- 微信开发者工具 公众号网页调试的调试器没了?
- Hangfire使用MySQL出现The Command Timeout expired before the operation completed
- Nginx反向代理后无法获取header带下划线的头信息
- 教你一招:Win10切换输入法与Win7一样(Ctrl + 空格)
- 华星充电:什么是新能源充电桩
- java程序封装最小单位,Java面试真题精选
- 刚兑换的电子优惠券竟被提前消费,原来是黑客做起倒爷生意
- web数据库管理和运维软件 - webcat
- 飞天技术汇 | 你用Kubernetes的样子很酷!
- java一元二次方程程序设计实验报告_Java 组件及事件处理实训 实训2:编写一个窗体程序,用于计算一元二次方程...
- miix5 u盘安装linux,联想Miix520 U盘装系统xp教程
- [UESTC1284] 郭大侠的苦恼
- 齐悟机器人王一_专注智能对话 王一校友当选“2020年度全美十大华人杰出青年”...
热门文章
- 快速增加闲鱼浏览量,就靠这些方法
- 【动手学深度学习】李沐——循环神经网络
- 海尔简爱s11装Linux,海尔简爱S11值得买吗 海尔简爱S11全面深度评测详解
- Oracle 创建表空间,创建表、数据增删改
- pycharm连接云端服务器后实现远程debug调试
- macOS、Linux CentOS 、Docker安装部署canal-server(canal-deployer)服务
- [2016 NUIST 程序设计竞赛] D. 达朗贝尔的台阶
- BIOS控制降频温度设置
- 微信上收到的文件怎么打印出来
- 中职一年级计算机英语课件,职高一年级英语期中试题