【快速学习系列】Mybatis缓存和使用SpringBoot开启MyBatis缓存+ehcache

news2024/10/7 7:35:50

【快速学习系列】Mybatis缓存和使用SpringBoot开启MyBatis缓存+ehcache

Mybatis缓存

MyBatis一级缓存

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库

tips:MyBatis一级缓存是默认开启

示例

写了一个分页查询的功能

测试类

@Test
public void findUserArrays() {
    SqlSession sqlSession = MyBatisUtil.createSqlSession();
    UserDao userDao = sqlSession.getMapper(UserDao.class);
    //测试mybatis一级缓存
    UserDao userDao1 = sqlSession.getMapper(UserDao.class);
    List<User> userList = userDao.findUserArrays(new Integer[]{1, 2}, 1);
    //调用两次方法但实际sql只执行一次(同sqlsession情况下且请求的方法和参数一致)
    List<User> userList1 = userDao1.findUserArrays(new Integer[]{1, 2}, 1);
    for (User user : userList) {
        System.out.println(user.toString());
    }

    MyBatisUtil.closeSqlSession(sqlSession);    //释放资源
}
结果

请添加图片描述

MyBatis二级缓存

MyBatis的二级缓存是**Application级别(也就是同一个SqlSessionFactory)**的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

tips:MyBatis二级缓存是默认不开启

开启二级缓存

SqlSessionFactory层面上的二级缓存默认是不开启的,二级缓存的开席需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置就可以开启缓存

步骤

1、在 MyBatis的配置文件 mybatis-config.xml中加入

<configuration>
    <settings>
        <!-- 开启mybatis二级缓存 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

2、在mapper.xml中开启二级缓存,mapper.xml下的sql执行完成会存储到它的缓存区

<!--回收策略为先进先出,每隔60秒刷新一次,最多缓存512个引用对象,只读-->
<cache  eviction="FIFO" flushInterval="60000"  size="512" readOnly="true"/>
<!--
参数说明:
eviction:
        LRU 最近最少使用的:移除最长时间不被使用的对象
        FIFO  先进先出:按对象进入缓存的顺序来移除它们
        SOFT 软引用:移除基于垃圾回收器状态和软引用规则的对象
        WEAK 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInterval :刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新(mia毫秒单位)
size :引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024
readOnly :(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false
-->
select,insert,update标签中的缓存属性
useCache=false,禁用二级缓存
<!-- 刷新缓存(每次执行相应的sql语句时) -->
flushCache=true 刷新缓存 ,一般用于insert,update

tips:这里我们可以看到,当设置二级缓存时,策略是控制整个mapper文件的,其实这样是非常不灵活的,我们更希望能够控制每一个业务方法都能够有不同的缓存策略,这样使用起来也是更符合实际开发的需要,所以下面的就是相对来说更好的一种缓存办法

使用SpringBoot开启MyBatis缓存+ehcache

事实上MyBatis自带的缓存还是有着一定缺陷的,而我们使用第三方的ehcache缓存则会更灵活

步骤

导入jar包

添加maven依赖

pom.xml

<!--添加缓存-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
   <groupId>net.sf.ehcache</groupId>
   <artifactId>ehcache</artifactId>
</dependency>

设置ehcache.xml配置

在项目的resources下新建一个名为ehcache.xml的配置文件,

然后把下面的代码粘过去即可

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下
             user.home :         用户主目录
             user.dir :          用户当前工作目录
             java.io.tmpdir :    默认临时文件路径
         -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
    <!--
    name:                            缓存名称
    eternal:                         true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false
    timeToIdleSeconds:               设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态
    timeToLiveSeconds:               设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义
    maxElementsInMemory:             内存中最大缓存对象数;maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行
    memoryStoreEvictionPolicy:       当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)
    maxElementsOnDisk:               硬盘中最大缓存对象数,若是0表示无穷大
    overflowToDisk:                  是否保存到磁盘,当系统宕机时
    diskPersistent:                  是否缓存虚拟机重启期数据,是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法
    diskSpoolBufferSizeMB:           这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
    diskExpiryThreadIntervalSeconds: 磁盘失效线程运行时间间隔,默认为120秒
    clearOnFlush:                    内存数量最大时是否清除
    -->
    <!--defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则默认缓存策略-->
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="true" diskPersistent="true" timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
    <!-- cache:自定义缓存策略,自己可以写多个然后针对不同的sql语句用于不同的情况中 -->
    <cache
            name="myCache"
            eternal="false"
            maxElementsInMemory="200"
            overflowToDisk="false"
            diskPersistent="true"
            timeToIdleSeconds="0"
            timeToLiveSeconds="300"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

上面标签可能会爆红,那个先不用管也没问题

使用@EnableCaching注解在启动类上开启缓存

@SpringBootApplication
@EnableCaching  //开启缓存
public class XXXXApplication {

    public static void main(String[] args) {
        SpringApplication.run(XXXXApplication.class, args);
    }

}

配置yml文件中缓存设置

首先需要开启MyBatis的二级缓存

# mybatis相关配置
mybatis:
  mapper-locations: classpath:mappers/*.xml
  type-aliases-package: com.r.springboot1.pojo    # xml映射文件中实体类起别名
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 在控制台打印日志信息
    cache-enabled: true  # 开启MyBatis的二级缓存

然后在配置中来读取我们刚刚写的缓存文件ehcache.xml

spring:
    cache:
        ehcache:
          config: classpath:ehcache.xml # 读取ehcache.xml缓存策略文件

Spring Cache注解使用

因为我们是使用注解来实现缓存,所以像原来在dao层映射文件中来配置缓存是没必要的,所以我们需要在Service的实现层来写缓存注解(注解可以是类上也可以是方法上)

@Cacheable

tips:如果使用时只写注解而不指定是哪个缓存策略的话,@Cacheable会自动执行默认策略😅

可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。

@Cacheable可以指定三个属性,value、key(使用key是为了让缓存数据之间能够有所区分,这样不会使其混乱)和condition (过滤条件)

不同配置方法示例
@Cacheable("myCache1")	//Cache是发生在ehcache.xml中myCache1上的
public User find(Integer id) {
    ....
}
@Cacheable({"cache1", "cache2"})	//Cache是发生在ehcache.xml中cache1和cache2上的(可以同时设置多个)
public User find(Integer id) {
    .....
}
//自定义策略是指我们可以通过Spring的EL表达式来指定我们的key
//#id指参数id作为key(按id区分同一个缓存策略中的不同缓存信息,使用唯一的id则不会使缓存混到一起出现问题)
@Cacheable(value="myCache1", key="#id")
public User find(Integer id) {
    ...
}
//#p0标识第一个参数作为key(p相当于param,#p0、#p1、#p2...依次代表第一个、第二个和第三个参数,以此类推)
@Cacheable(value="myCache1", key="#p0")
public User find(Integer id) {
    .....
}
//#user.user_id表示对象user属性user_id作为key(可以用对象的属性作为key用来区分,当然id还是唯一的字段,使用起来不会使缓存混乱)
@Cacheable(value="myCache1", key="#user.user_id")
public User find(User user) {
    .....
}
//也可以混着这样用
@Cacheable(value="myCache1", key="#p0.user_id")
public User find(User user) {
    .....
}
Spring还为我们提供了一个root对象可以用来生成key
示例描述
root.methodName当前方法名
root.method.name当前方法
root.target当前被调用的对象
root.targetClass当前被调用的对象的class
root.args[0]当前方法参数组成的数组
root.caches[0].name当前被调用的方法使用的Cache

condition使用

//表示只有当user的id为偶数时才会进行缓存   
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")   
public User find(User user) {    ...   }
使用key的情景

key不是什么时候都适合使用

当要显示一些共享的缓存信息时,没有必要使用key(key适用于将缓存信息独立分离开进行缓存的情况)

在一些未知且经常变化的参数上,没有必要使用key(key适用于缓存一些有限的、且唯一的参数字段上,就比如id)

注意事项

使用的方法实体类必须经过序列化,否则会报错

请添加图片描述

报错显示所用的实体类为进行序列化,但同时也证明缓存的确是在运行着

给实体类序列化示例

implements Serializable即可

public class Provider implements Serializable {}

然后运行自己的方法后我们可以在控制台看到,虽然多次请求,但因为我们设置了缓存,会发现sql语句只运行了一次,这也说明我们的缓存设置成功

请添加图片描述

@CachePut

使用@CachePut时我们可以指定的属性跟@Cacheable是一样的

@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中

也就是说@Cacheable每次执行前都会先看一下之前是否有缓存,如果有就用原来存在的缓存,而@CachePut每次执行都直接刷新缓存,不会看之前是否存在缓存

@CacheEvict

清除缓存, 可以指定的属性有value、key、condition、allEntries、beforeInvocation

tips:一般用于增删改上,因为我们定义的缓存策略中可能存在当我们增删改时还没有过缓存时间,所以这时候就会显示还没有改的样子,所以我们为了能够改变后即刻刷新缓存,所以需要用到这个

使用示例
@CacheEvict(value="myCache",key="#p0.user_id")
public int updUser(SfUser user) throws Exception {
    return sfUserMapper.updUser(user);
}
//allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率(false时指执行方法时,我只清除对应id方法的这一条,true是执行方法时,所有的缓存都清掉,当再次执行有@Cacheable的方法时缓存再被再次加入)
    @CacheEvict(value="users", allEntries=true)
    public void delete(Integer id) {
    System.out.println("delete user by id: " + id);
}

tips:如果使用@CacheEvict的时候不设置key,那么它会清除掉当前所有的缓存(当然清楚的是你设置的当前方法中配置的相应缓存策略,并不是说所有的完完全全的缓存全清除了😁)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全员全域安全守护,蔚来ET7获Euro NCAP五星安全评级背后的硬核实力

2022年11月16日&#xff0c;蔚来智能电动旗舰轿车ET7 获得Euro NCAP&#xff08;欧盟新车安全评鉴协会&#xff09;五星安全评级&#xff0c;成为继ES8之后蔚来又一款获得欧洲五星安全评级的车型。ET7分别在乘客安全、儿童安全、弱势道路使用者安全、辅助安全得分91%、87%、73%…

两个事务并发写,能保证数据唯一吗?

哟&#xff0c;又是我小白。最近有点高产了。 连我自己都害怕了。 直接进入正题吧。 两个事务并发写&#xff0c;能保证数据唯一吗&#xff1f; 我先来解释下标题讲的是个啥。 我们假设有这么一个用户注册的场景。用户并发请求注册新用户。 你有一张数据库表&#xff0c;也就…

【数据可视化】第二章——基于matplotlib的数据可视化

目录系列课程学习目标1. 基于matplotlib的数据可视化2 matplotlib.pyplot函数库简介3 matplotlib.pyplot相关函数简介3.1 plt.plot(x, y, format_string, **kwargs)3.2 plt.title()3.3 plt.xlabel()/ylabel()3.4 plt.legend()3.5 pyplot的中文显示3.5.1 第一种方法3.5.2 第二种…

C#上位机系列(2)—常用控件的介绍:文本标签,按键,输入框

本文是讲解C#.net平台的Winform框架下的第二个内容&#xff0c;手把手介绍项目的创建方式以及一些写软件时常用的功能&#xff0c;讲解从零开始的每一个步骤。 本次介绍三个最常用控件的使用 1.文本控件Label 功能&#xff1a;显示一个文本 2.按键控件Button 功能&#x…

考研 | 组成原理【第二章】数据的表示和运算

考研 | 组成原理【第二章】数据的表示和运算 文章目录考研 | 组成原理【第二章】数据的表示和运算I. 数制与编码a. 进位计数制及其相互转换b. BCD码1. 8421码2. 余3码3. 2421码c. 无符号整数表示和运算1. 表示2. 运算d. 带符号整数的表示和运算1. 原码2. 反码3. 补码4. 移码5. …

多肽标签VSV-G Tag、YTDIEMNRLGK

VSV-G肽是一种源自水泡性口腔炎病毒糖蛋白的11个氨基酸的肽。编号: 191225 中文名称: 多肽标签VSV-G Tag 英文名: VSV-G Tag 英文同义词: VSV tag 单字母: H2N-YTDIEMNRLGK-OH 三字母: H2N-Tyr-Thr-Asp-Ile-Glu-Met-Asn-Arg-Leu-Gly-Lys-COOH 氨基酸个数: 11 分子式: C57H94N16…

【HMS Core】ScanPlus和Push推送库出现冲突该如何解决?

1、问题描述 项目中之前是同时集成了华为统一扫码服务SDK和华为推送SDK&#xff0c;这两天升级华为推送版本至6.3.0.304时发现这两个库出现了冲突&#xff0c; 这两个库的依赖版本情况如下所示&#xff1a; implementation com.huawei.hms:scanplus:2.7.0.301 implementatio…

[附源码]java毕业设计小型医院药品及门诊管理

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

《垃圾回收算法手册 自动内存管理的艺术》——内存分配(笔记)

文章目录七、内存分配7.1 顺序分配7.2 空闲链表分配7.2.1 首次适应分配7.2.2 循环首次适应分配7.2.3 最佳适应分配7.2.4空闲链表分配的加速快速适应分配(fast-fit allocation)位图适应分配(bitmapped-fits allocation)7.3 内存碎片化7.4 分区适应分配7.4.1 内存碎片7.4.2 空间大…

LINUX SECCOMP模块介绍

SECCOMP介绍 Seccomp是 "secure computing" 的 缩写。Linux内核2.6.12版本&#xff08;2005年3月8日&#xff09;引入。是linux一个安全模块&#xff0c;用于限制程序系统调用&#xff1b;当时如果使用了SECCOMP只允许4个系统调用&#xff1a; read&#xff0c;wri…

Flutter组件--Padding和AnimatedPadding

示意图: Padding介绍 在应用程序中有许多widget 时&#xff0c;这个时候画面常常会变得很拥挤&#xff0c;这个时候如果想要在widget之间来保留一些间距&#xff0c;那就用 Padding 为什么使用 Padding 而不使用 Container.padding 属性的 Container? Container 是将许多更…

RabbitMQ-08 不公平分发与预取值

不公平分发 我们之前演示的所有示例都遵循轮询分发&#xff0c;也就是多个消费者时交替消费队列消息。可以想一下我们之前的一个例子。Worker02处理消息只需要1s但是Worker03处理一个消息却用30s的情况。那么这个时候我们就要使用到不公平分发。简而言之就是能者多劳。 需要在消…

亚马逊刷单测评的正确方法是什么样的?

做亚马逊刷单测评时想要有效果&#xff0c;测评方法很重要&#xff0c;不能直接通过链接进行下单&#xff0c;这样显的很不真实&#xff0c;如果是要找人帮忙测评&#xff0c;可以通过以下方式进行&#xff1a; 1、通过关键词搜索进入 选择自己想刷的关键词&#xff0c;直接搜…

物联网安全年报小结

小结 不仅仅是 LockerGoga&#xff0c;其他勒索软件也对工业系统造成了重大损失&#xff0c;如全球第二大听力集团 Demant 被勒索造成损失达 9500 万美元 [21]&#xff1b;世界上最大的飞机零部件供给商之一 ASCO&#xff0c;因其位于 比利时扎芬特姆的工厂系统遭勒索病毒传染…

目标检测算法——YOLOv5/YOLOv7改进之结合​RepVGG(速度飙升)

>>>深度学习Tricks&#xff0c;第一时间送达<<< 目录 RepVGG——极简架构&#xff0c;SOTA性能&#xff01;&#xff01;&#xff01; &#xff08;一&#xff09;前沿介绍 1.RepVGGBlock模块 2.相关实验结果 &#xff08;二&#xff09;YOLOv5/YOLOv7改…

Alibaba官方上线,SpringBoot+SpringCloud全彩指南(第五版)

Alibaba作为国内一线互联网大厂&#xff0c;其中springcloudAlibaba更是阿里微服务最具代表性的技术之一&#xff0c;很多人只知道springcloudAlibaba其实面向微服务技术基本上都有的下面就给大家推荐一份Alibaba官网最新版&#xff1a;SpringBootSpringCloud微服务全栈开发小册…

基于STM32G431嵌入式学习笔记——三、KEY按键入门

一、按键在CubeXM里的配置 可以打开先前配置过LED的CubeMX&#xff0c;在其基础上进行按键的配置。 个人建议在这里先将原环境拷贝 更改副本文件夹名为LED_KEY_LCD 打开文件夹中的.ioc文件进行配置 在配置之前&#xff0c;我们先查阅产品手册了解按键的电路图&#xff0c;以…

07-Nginx 日志管理及自动切割

Nginx 日志管理及自动切割 对于程序员、运维来说&#xff0c;日志非常得重要。通过日志可以查看到很多请求访问信息&#xff0c;及异常信息。Nginx 也提供了对日志的强大支持。 日志管理范围 首先&#xff0c;下面要讲的这些日志相关属性可以配置在任意模块。在不同的模块&…

如果我在初用tomcat时,是看到这篇tomcat架构解析,是不是就不会被说菜鸡了!

写在前面 tomcat作为一个中间件&#xff0c;相信绝大多数java程序员&#xff0c;多多少少都应该用到过吧。尤其是在springboot还未流行的时候&#xff0c;本地环境&#xff0c;没少跑tomcat服务吧&#xff1f; 我们一般都是直接使用&#xff0c;将我们的web服务&#xff0c;直…

疫情下跨越一万公里的友情:熊超与飒特电子哨兵的故事

在熊超&#xff08;化名&#xff09;家中&#xff0c;有一面照片墙&#xff0c;上面贴满了他在非洲工作十多年的剪影。这些照片整齐地摆放成一个心形&#xff0c;挂在客厅最显眼的位置。每当亲戚朋友来访&#xff0c;熊超都会为他们讲起自己援助非洲十余年发生的故事。 十多年…