缓存实现的方式

  • 一级缓存
  • 二级缓存

案例实操

1. 一级缓存

基于 PerpetualCache 的 HashMap 本地缓存(mybatis 内部实现 cache 接口),其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空;

2. 二级缓存

一级缓存其机制相同,默认也是采用 PerpetualCache 的 HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache;

对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存 Namespaces)的进行了 C/R/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

如果二缓存开启,首先从二级缓存查询数据,如果二级缓存有则从二级缓存中获取数据,如果二级缓存没有,从一级缓存找是否有缓存数据,如果一级缓存没有,查询数据库

3. 二级缓存局限性

mybatis 二级缓存对细粒度的数据级别的缓存实现不好,对同时缓存较多条数据的缓存,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用 mybatis 的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为 mybaits 的二级缓存区域以 mapper 为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空

4. 一级缓存(默认开启)

Mybatis 默认提供一级缓存,缓存范围是一个 sqlSession。在同一个 SqlSession 中,两次执行相同的 sql 查询,第二次不再从数据库查询。

原理:一级缓存采用 Hashmap 存储,mybatis 执行查询时,从缓存中查询,如果缓存中没有从数据库查询。如果该 SqlSession 执行 clearCache() 提交或者增加删除修改操作,清除缓存。

默认就存在,了解观察结果即可

a.缓存存在情况(session 未提交)

@Test
​
public void test01() {
​SqlSession sqlSession=sqlSessionFactory.openSession();
​AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
​Account account=accountDao.queryAccountById(1);
​System.out.println(account);
​accountDao.queryAccountById(1);
​
} 

日志仅打印一条 sql

b.刷新缓存

Session 提交此时缓存数据被刷新

@Test
public void test02() { SqlSession sqlSession=sqlSessionFactory.openSession();  AccountDao accountDao=sqlSession.getMapper(AccountDao.class);  Account account=accountDao.queryAccountById(1); System.out.println(account); sqlSession.clearCache(); accountDao.queryAccountById(1);
} 

效果:

5. 二级缓存

一级缓存是在同一个 sqlSession 中,二级缓存是在同一个 namespace 中,因此相同的 namespace 不同的 sqlsession 可以使用二级缓存。

使用场景

  • 对查询频率高,变化频率低的数据建议使用二级缓存。
  • 对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用 mybatis 二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析 sql、电话账单查询 sql 等。

全局文件配置(mybatis.xml)

<setting name="cacheEnabled" value="true"/>
Mapper.xml 中加入 :打开该 mapper 的二级缓存
​
<!-- 开启该 mapper 的二级缓存 -->
​
<cache/>

cache 标签常用属性

<cache
​
eviction="FIFO" <!--回收策略为先进先出-->
​
flushInterval="60000" <!--自动刷新时间 60s-->
​
size="512" <!--最多缓存 512 个引用对象-->
​
readOnly="true"/> <!--只读--> 

说明:

  1. 映射语句文件中的所有 select 语句将会被缓存。
  2. 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
  3. 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
  4. 缓存会根据指定的时间间隔来刷新.
  5. 缓存会存储 1024 个对象

PO 对象必须支持序列化

public class User implements Serializable {
​
} 

关闭 Mapper 下的具体的 statement 的缓存

使用 useCache:默认为 true

<select id="findUserByid" parameterType="int" resultType="User"
​
useCache="false">
​SELECT * FROM user WHERE id=#{id}
​
</select> 

刷新二级缓存

操作 CUD 的 statement 时候,会强制刷新二级缓存 即默认 flushCache="true" ,如果想关闭设定为 flushCache="false"即可 ,不建议关闭刷新,因为操作更新删除修改,关闭后容易获取脏数据。

二级缓存测试:

@Test
​
public void test03() {
​SqlSession sqlSession=sqlSessionFactory.openSession();
​AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
​Account account=accountDao.queryAccountById(1);
​System.out.println(account);
​sqlSession.close();
​SqlSession sqlSession2=sqlSessionFactory.openSession();
​AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);
​accountDao2.queryAccountById(1);
​sqlSession.close();
​
} 

效果:

扩展

分布式缓存 ehcache

如果有多条服务器 ,不使用分布缓存,缓存的数据在各个服务器单独存储,不方便系统开发。所以要使用分布式缓存对缓存数据进行集中管理。因此可是使用 ehcache memcached redis

mybatis 本身来说是无法实现分布式缓存的,所以要与分布式缓存框架进行整合。 EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点;Ehcache 是一种广泛 使用的开源 Java 分布式缓存。主要面向通用缓存,Java EE 和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个 gzip 缓存 servlet 过滤器,支持 REST 和 SOAP api 等特点。

Jar 依赖

<dependency>
​<groupId>net.sf.ehcache</groupId>
​<artifactId>ehcache-core</artifactId>
​<version>2.4.4</version>
​
</dependency>
​
<dependency>
​<groupId>org.mybatis.caches</groupId>
​<artifactId>mybatis-ehcache</artifactId>
​<version>1.0.3</version>
​
</dependency> 

缓存接口配置

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/> 

在 src 下 加入 ehcache.xml(不是必须的没有使用默认配置)

<?xml version="1.0" encoding="UTF-8"?>
​
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
​
xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd">
​
<!--
​
name:Cache 的唯一标识
​
maxElementsInMemory:内存中最大缓存对象数
​
maxElementsOnDisk:磁盘中最大缓存对象数,若是 0 表示无穷大
​
eternal:Element 是否永远不过期,如果为 true,则缓存的数据始终有效,如果为 false
​
那么还要根据 timeToIdleSeconds,timeToLiveSeconds 判断
​
overflowToDisk:配置此属性,当内存中 Element 数量达到 maxElementsInMemory 时,
​
Ehcache 将会 Element 写到磁盘中
​
timeToIdleSeconds:设置 Element 在失效前的允许闲置时间。仅当 element 不是永久有效
​
时使用,可选属性,默认值是 0,也就是可闲置时间无穷大
​
timeToLiveSeconds:设置 Element 在失效前允许存活时间。最大时间介于创建时间和失效
​
时间之间。仅当 element 不是永久有效时使用,默认是 0.,也就是 element 存活时间无穷
​
大
​
diskPersistent:是否缓存虚拟机重启期数据
​
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是 120 秒
​
diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区大小。默认是
​
30MB。每个 Cache 都应该有自己的一个缓冲区
​
memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将会根据
​
指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为 FIFO(先进先
​
出)或是 LFU(较少使用)
​
-->
​
<defaultCache overflowToDisk="true" eternal="false"/>
​
<diskStore path="D:/cache" />
​
<!--
​
<cache name="sxtcache" overflowToDisk="true" eternal="false"
​
timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="1000"
​
maxElementsOnDisk="10" diskPersistent="true"
​
diskExpiryThreadIntervalSeconds="300"
​
diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU" />
​
--> 

测试:

@Test
​
public void test04() {
​SqlSession sqlSession=sqlSessionFactory.openSession();
​AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
​Account account=accountDao.queryAccountById(1);
​System.out.println(account);
​sqlSession.close();
​SqlSession sqlSession2=sqlSessionFactory.openSession();
​AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);
​accountDao2.queryAccountById(1);
​sqlSession.close();
​
} 

mybatis执行opensession时空指针异常_关于 Mybatis 缓存的那点事儿,你知道吗?相关推荐

  1. mybatis plus 事务管理器_学习MyBatis 框架

    1. 框架是什么? a 框架就就是写好的功能架构 一些重复的代码的深度的封装 b 框架也是一个半成品 调用同时 也需要告诉框架一些信息 c一般以配置文件方式告知框架 多数会使用Xml作为框架的配置文件 ...

  2. mybatis传递多个参数_深入浅出MyBatis:MyBatis解析和运行原理

    原文:https://juejin.im/post/5abcbd946fb9a028d1412efc 本篇文章是「深入浅出MyBatis:技术原理与实践」书籍的总结笔记. 上一篇介绍了反射和动态代理基 ...

  3. mybatis map里面传对象_关于 MyBatis,我死磕了 10 种超好用的写法

    用来循环容器的标签forEach,查看例子 foreach元素的属性主要有item,index,collection,open,separator,close. item:集合中元素迭代时的别名, i ...

  4. 无法对 null 引用执行运行时绑定_你真的懂this吗?聊聊默认绑定,隐式绑定,显示绑定,new绑定...

    https://github.com/YvetteLau/Blog/issues/6 this关键字是JavaScript中最复杂的机制之一,是一个特别的关键字,被自动定义在所有函数的作用域中,但是相 ...

  5. mybatis delete返回值_面试:谈谈你对MyBatis执行过程之SQL执行过程理解

    前言 在了解了MyBatis初始化加载过程后,我们也应该研究看看SQL执行过程是怎样执行?这样我们对于Mybatis的整个执行流程都熟悉了,在开发遇到问题也可以很快定位到问题. 更重要的,在面试中遇到 ...

  6. Mybatis执行流程分析_自定义简易Mybatis框架

    自定义简易Mybatis框架 Mybatis执行流程分析 Mybatis代码编写流程: Mybatis配置文件加载过程: 需求分析及技术概述 根据上述的功能结构图, 得出如下需求: 1. 需要具有配置 ...

  7. statement执行insert into语句_【图文并茂】源码解析MyBatis ShardingJdbc SQL语句执行流程详解...

    源码分析Mybatis系列目录: 1.源码分析Mybatis MapperProxy初始化[图文并茂] 2.源码分析Mybatis MappedStatement的创建流程 3.[图文并茂]Mybat ...

  8. mybatis insert 返回主键_面试准备季——MyBatis 面试专题(含答案)

    话不多说,直接上题-- 1.什么是 Mybatis? (1)Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL 语句本身,不需要花费精力去处理加载驱 ...

  9. 当面试官问我Mybatis初始化原理时,我笑了

    对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章将通过以下几点详细介绍MyBatis的初始化过程. MyBatis的初始化做了什么 MyBatis基于XML配置文件创建C ...

  10. mybatis一个方法执行多条sql_精尽MyBatis源码分析——SQL执行过程之Executor!

    MyBatis的SQL执行过程 在前面一系列的文档中,我已经分析了 MyBatis 的基础支持层以及整个的初始化过程,此时 MyBatis 已经处于就绪状态了,等待使用者发号施令了 那么接下来我们来看 ...

最新文章

  1. SAP MM 特殊库存之T库存
  2. 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
  3. python java
  4. Oracle-RAC安装随笔
  5. Apollo进阶课程㉓丨Apollo规划技术详解——Motion Planning with Environment
  6. 第33课 打擂台 《小学生C++趣味编程》
  7. 金蝶记账王登录显示连接金蝶云服务器异常,金蝶KIS记账王系统初始化常见问题...
  8. 【Java】JDK8新特性之方法引用
  9. 量子计算机有哪些战略意义,世界性颠覆!量子计算机在中国诞生,对我国有五层重大战略意义!...
  10. 无线传感器网络复习大纲
  11. 马士兵struts2视频教程第六集
  12. 中文TTS文字转语言合成模块
  13. 计算机应用软件安装不了,应用程序无法正常启动,详细教您电脑应用程序无法正常启动0xc000007b怎么解决...
  14. php调用和风天气api,推荐一个免费7天天气预报API服务:和风天气
  15. c语言用while实现输出加法口诀表,「加法口诀」C语言编写一个加法口诀表 - 金橙教程网...
  16. Qt-qrc资源文件-rcc打包-程序调用-ZIP压缩和解压-安装程序制作参考
  17. 面向智慧教室物联网关键技术的研究与运用(待完成)
  18. 可能是全网唯一一个基于windows和java的关于selenium webDriver绕过网站反爬服务的方法
  19. 推荐五款浏览器实用插件,总有几个是你需要的
  20. 【报告】当“无线通信”遇到“图神经网络”——简单理解

热门文章

  1. asp.net 获取计算机启动时间
  2. Python备份文件实现以及备份大文件出错解决方案
  3. 使用libevhtp编写HTTP服务器的方法
  4. 支持向量机原理(三)线性不可分支持向量机与核函数
  5. 笔试+面试信息整理----面向笔试学习、面向面经编程
  6. bzoj1853幸运数字——容斥原理
  7. [转]ASP.NET MVC IOC 之AutoFac攻略
  8. EMNLP'21中预训练模型最新研究进展
  9. ICLR 审稿人:这篇论文在标签平滑和知识蒸馏的关系上取得了重大突破!
  10. 【实践】BiLSTM上的CRF,用命名实体识别任务来解释CRF(1)