文章目录

  • 项目准备
    • 新建项目并选择模块安装
    • 添加依赖
    • 添加application.yml
    • 删除demos.web包
    • 编写pojo层
      • user
      • dto/ResultJson
    • 编写mapper层
      • UserMapper
    • 编写service层
      • UserService
    • 编写controller层
    • 编写配置类
      • MybatisPlusConfig
    • 编写测试类
  • 1 缓存分类
    • 1.1 MyBatis一级缓存
    • 1.2 MyBatis二级缓存
      • 1.2.1 开启二级缓存
      • 1.2.2 Mybatis开启使用二级缓存
  • 2 SpringBoot使用缓存
    • 2.1 SpringBoot开启MyBatis缓存+ehcache
      • 2.1.1 引入依赖
      • 2.1.2 添加缓存的配置文件 ehcache.xml
      • 2.1.3 读取ehcache.xml文件
      • 2.1.4 设置项目启动时使用缓存
      • 2.1.5 序列化你的pojo层
    • 2.2 缓存的使用
      • 2.2.1 基本使用
      • 2.2.2 @Cacheable注解使用
      • 2.2.2 @CachePut
      • 2.2.3 @CacheEvict
  • 3 SpringBoot+Redis使用
    • 3.1 Redis 缓存配置
      • 3.1.1 引入依赖
      • 3.1.2 yml添加配置
      • 3.1.3 序列化
    • 3.2 Cacheable 注解
    • 3.3 多参数 Cacheable 注解
    • 3.4 缓存的清除 @CacheEvict
    • 3.5 yml配置
    • 3.6 缓存管理
      • 3.6.1 编写MyRedisCacheManager配置类
      • 3.6.2 编写CacheConfig
      • 3.6.3 演示

项目准备

新建项目并选择模块安装

创建一个空的 Spring Boot 工程
文件–>新建项目
在这里插入图片描述

选择模块

  1. SpringBoot版本选择2.7.6
  2. DeveloperTools中选择Lombok
  3. Web中选择SpringWeb
  4. SQL中选择MySQLDriver
    在这里插入图片描述

添加依赖

<!-- mybatis-plus依赖 -->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version><!--sql性能分析插件使用版本--><!-- <version>3.1.2</version> -->
</dependency>

添加application.yml

我们删除application.properties
在resources文件下新建application.yml.
application.yml 中配置文件中添加mysql 数据库相关配置:

server:port: 8080
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: root
# mybatis-plus 相关配置
mybatis-plus:type-aliases-package: com.hsh.pojo #类型别名所在的包#控制台打印sql语句configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: false #关闭驼峰映射

注意你要写你的数据库端口号账号密码你要简化的包名 这些一定要看一下。

删除demos.web包

在这里插入图片描述

编写pojo层

user

com/hsh/pojo/user

package com.hsh.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("smbms_user")
public class User {private Long id;// 主键IDprivate String userCode;// 用户编码private String userName;// 用户名称private String userPassword;// 用户密码private Integer gender;// 性别(1:女、 2:男)private LocalDateTime birthday;//  出生日期private String phone;//  手机private String address;//  地址private Long userRole;// 用户角色(取自角色表-角色id)private Long createdBy;// 创建者(userId)private LocalDateTime creationDate;// 创建时间private Long modifyBy; // 更新者(userId)private LocalDateTime modifyDate; // 更新时间
}

dto/ResultJson

package com.hsh.pojo.tdo;
import java.io.Serializable;@Data
public class ResultJSON<T> implements Serializable {private Integer code;private String msg;private T data;public ResultJSON(Integer code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}/*** 操作成功或者失败* @param c 受影响行数* @return 当前传入的受影响行数>0则返回成功,否则返回失败*/public static  ResultJSON successORerror(int c){return c>0?new ResultJSON(200,"操作成功",c):new ResultJSON(400,"操作失败",c);}public static ResultJSON success(){return new ResultJSON(200,"操作成功",null);}public static ResultJSON success(String msg){return new ResultJSON(200,msg,null);}public static <T> ResultJSON success(T data){return new ResultJSON(200,"操作成功",data);}public static ResultJSON success(Integer code,String msg){return new ResultJSON(code,msg,null);}public static <T> ResultJSON success(String msg,T data){return new ResultJSON(200,msg,data);}public static <T> ResultJSON success(Integer code,String msg,T data){return new ResultJSON(code,msg,data);}public static ResultJSON error(){return new ResultJSON(500,"操作失败",null);}public static ResultJSON error(String msg){return new ResultJSON(500,msg,null);}public static ResultJSON error(Integer code,String msg){return new ResultJSON(code,msg,null);}}

编写mapper层

UserMapper

package com.hsh.mapper;public interface UserMapper extends BaseMapper<User> {}

编写service层

UserService

// 接口
package com.hsh.service;
public interface UserService {ResultJSON<User> getUserById(Long id);
}
// 实现类
package com.hsh.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hsh.mapper.UserMapper;
import com.hsh.pojo.User;
import com.hsh.pojo.dto.ResultJSON;
import com.hsh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic ResultJSON<User> getUserById(Long id) {User user = userMapper.selectById(id);return ResultJSON.success(user);}
}

编写controller层

package com.hsh.controller;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/getUserById")public ResultJSON getUserById(Long id){return ResultJSON.success(userService.getUserById(id));}
}

编写配置类

MybatisPlusConfig

package com.hsh.config;@Configuration
@MapperScan("com.hsh.mapper")
public class MybatisPlusConfig {}

编写测试类

package com.hsh;import com.hsh.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class MybatisPlus01ApplicationTests {@Autowiredprivate UserMapper userMapper;@Testvoid contextLoads() {System.out.println(userMapper.selectById(1));}
}

在这里插入图片描述

1 缓存分类

1.1 MyBatis一级缓存

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

1.2 MyBatis二级缓存

MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

1.2.1 开启二级缓存

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

1.2.2 Mybatis开启使用二级缓存

修改配置文件mybatis-config.xml加入

<setting name="cacheEnabled"value="true"/>

在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,禁用二级缓存
flushCache=true 刷新缓存 ,一般用于insert,update(目前版本可以自动刷新)

2 SpringBoot使用缓存

2.1 SpringBoot开启MyBatis缓存+ehcache

2.1.1 引入依赖

引入缓存的依赖包,在配置 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>

2.1.2 添加缓存的配置文件 ehcache.xml

标签解释

  1. diskStore标签:指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下
    • user.home 属性: 用户主目录
    • user.dir属性 : 用户当前工作目录
    • java.io.tmpdir属性 : 这是 Java 虚拟机的默认​​临时文件路径​​。默认临时文件路径。例如,在 Windows 系统中可能是 C:\Users[用户名]\AppData\Local\Temp`
  2. defaultCache标签:默认缓存策略,当ehcache找不到定义的缓存时,则默认缓存策略。
    • 属性同下面的cache。只不过他没有name属性
  3. cache:自定义的缓存策略。(可以有多个cache标签)
    1. name: 缓存名称
    2. eternal: true表示对象永不过期,此时会忽略 timeToIdleSeconds和timeToLiveSeconds属性,默认为false
    3. timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了。timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态
    4. timeToLiveSeconds: 设定对象允许存在于缓存中的最长时间,以秒为单位。当对
      象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义。
    5. maxElementsInMemory: 内存中最大缓存对象数;maxElementsInMemory界限
      后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行
    6. memoryStoreEvictionPolicy: 当达到maxElementsInMemory限制时,Ehcache将会根
      据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)
    7. maxElementsOnDisk: 硬盘中最大缓存对象数,若是0表示无穷大
    8. overflowToDisk: 是否保存到磁盘,当系统宕机时
    9. diskPersistent: 是否缓存虚拟机重启期数据,是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法。
    10. diskSpoolBufferSizeMB: 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
    11. diskExpiryThreadIntervalSeconds: 磁盘失效线程运行时间间隔,默认为120秒。
    12. clearOnFlush: 内存数量最大时是否清除。

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

2.1.3 读取ehcache.xml文件

在application.properties配置中读取ehcache.xml文件

#读取缓存配置文件
spring.cache.ehcache.config=classpath:ehcache.xml#最后记得开启打印sql语句,方便测试,下面二选一
logging.level.com.hz.dao=debug
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.1.4 设置项目启动时使用缓存

@SpringBootApplication
@EnableCaching //开启缓存
public class Springboot1Application {public static void main(String[] args) {SpringApplication.run(Springboot1Application.class, args);}
}

2.1.5 序列化你的pojo层

pojo/dto/ResultJSON

package com.hsh.pojo.dto;@Data
public class ResultJSON<T> implements Serializable {// ....
}

pojo/user

package com.hsh.pojo;@Data
@TableName("smbms_user")
public class User implements Serializable {//....
}

2.2 缓存的使用

2.2.1 基本使用

在service层加上@Cacheable("myCache")这个myCache是指定上面的cache标签的name。如果不写使用<defaultCache/>

package com.hsh.service.impl;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate UserMapper userMapper;@Override@Cacheable(value = "myCache", key = "#id")public ResultJSON<User> getUserById(Long id) {User user = userMapper.selectById(id);return ResultJSON.success(user);}
}

访问http://localhost:8080/user/getUserById?id=1多次刷新
idea控制台日志只输出一次说明缓存使用成功。

2.2.2 @Cacheable注解使用

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

@Cacheable可以指定三个属性,value、key和condition

  1. key = "#id"的作用
    key = "#id"是一个 ​​SpEL(Spring Expression Language)表达式​​,它指定了缓存项的​​唯一标识符(缓存键)​​。具体作用是:
    • #id​​:表示使用该方法入参中的 id的值作为缓存键。
    • 例如,当你调用 getUserById(123L)时,Spring 会以 123为键,将查询到的 User对象存储在名为 "myCache"的缓存区域中。
    • 下次再调用 getUserById(123L),Spring 会先检查 "myCache"缓存区域中是否存在键为 123的数据。如果存在,则直接返回该缓存数据,不再执行 userMapper.selectById(id)和数据库查询。
  2. 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
@Cacheable(value="myCache1", key="#id")
public User find(Integer id) {
...
}
//#p0标识第一个参数作为key
@Cacheable(value="myCache1", key="#p0")
public User find(Integer id) {
.....
}
//#user.user_id表示对象user属性user_id作为key
@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
//表示只有当user的id为偶数时才会进行缓存
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
...
}

2.2.2 @CachePut

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

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

2.2.3 @CacheEvict

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

@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一下清除所有的元素,这比一个一个清除元素更有效率。
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {System.out.println("delete user by id: " + id);
}

3 SpringBoot+Redis使用

当我们的应用程序需要频繁地读取和写入数据时,为了提高应用程序的性能,我们通常会使用缓存技术。Spring Boot 提供了一种简单而强大的缓存框架,它可以轻松地将数据缓存到 Redis 中。

在 Spring Boot 中可以在方法上简单的加上注解实现缓存。

3.1 Redis 缓存配置

3.1.1 引入依赖

首先,您需要在您的项目中添加 Redis 的依赖。您可以将以下依赖添加到您的项目的 pom.xml 文件中:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3.1.2 yml添加配置

一旦 Redis 的依赖被添加,您需要配置 Redis 的相关信息。以下是一个示例 Redis 配置:

spring:redis:host: 127.0.0.1port: 6379password:database: 0

在上述配置文件中,host 和 port 属性指定了 Redis 服务器的主机名和端口号,password 属性用于指定 Redis 服务器的密码(如果有的话),而 database 属性则指定了 Redis 服务器使用的数据库编号。

3.1.3 序列化

Redis 的默认序列化器是 JdkSerializationRedisSerializer,但是在实际使用中,由于其序列化后的大小通常比较大,因此我们通常使用 StringRedisSerializer 或者 Jackson2JsonRedisSerializer 将缓存值序列化为字符串或者 JSON 格式。以下是一个自定义序列化器的示例:

package com.hsh.config;@Configuration
public class RedisConfig {/*** redisTemplate 默认使用JDK的序列化机制, 存储二进制字节码, 所以自定义序列化类* @param redisConnectionFactory redis连接工厂类* @return RedisTemplate*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置value的序列化规则和 key的序列化规则redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

在此示例中,我们通过自定义 Bean 配置了 RedisTemplate,使用 StringRedisSerializer 序列化 Redis键,并使用 Jackson2JsonRedisSerializer 序列化 Redis 值为 JSON 格式。

可以再测试类中验证使用一下

package com.hsh;@SpringBootTest
class CacheApplicationTests {@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;@Testvoid contextLoads() {User user = new User();user.setId(1L);user.setUserName("hsh");redisTemplate.opsForValue().set("user1", user);System.out.println(redisTemplate.opsForValue().get("user1"));}
}

打开redis可视化工具查看。
在这里插入图片描述

3.2 Cacheable 注解

我们知道上面ehcache已经使用@Cacheable注解了,此时这个Redis也使用了这个注解。idea可能会报错,
如果报错解决办法:将上面引入的spring-boot-starter-cacheehcache的依赖注释掉就行。

使用 Cacheable 注解来标记需要进行缓存的方法。以下是一个具有 Cacheable 注解的示例方法:同样还是在service实现类的方法上编写。

package com.hsh.service.impl;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate UserMapper userMapper;@Override@Cacheable(value = "users")public ResultJSON<User> getUserById(Long id) {User user = userMapper.selectById(id);return ResultJSON.success(user);}
}

访问http://localhost:8080/user/getUserById?id=1
打开Redis的可视化窗口查看。
在这里插入图片描述

在这个例子中,@Cacheable 注解用于标记 getUserById 方法,而 value 属性则用于指定缓存的存储区域的名称。由于我们正在使用 Redis 作为缓存,因此 Redis 中的 key 将由 Cacheable 注解中的 key 属性指定。在此示例中,key 属性设置为 “#id”,这意味着我们将使用方法参数 id 作为 Redis 缓存的键。

3.3 多参数 Cacheable 注解

在某些情况下,我们需要以多个参数作为 key 来缓存数据。此时,我们可以对 key 属性使用表达式language(SpEL)来设置多个参数:

@Servicepublic class UserService {
@Cacheable(value = "users", key = "#id + '_' + #name")public User getUserByIdAndName(Long id, String name) {// 查询用户并返回}
}

在上述示例中,我们使用了表达式语言(SpEL)将 id 和 name 两个参数组合成了一个 Redis 缓存键。

3.4 缓存的清除 @CacheEvict

有时候,您需要清除 Redis 缓存中的某些数据,以便在下一次访问时重建缓存。在 Spring Boot 中,可以使用 @CacheEvict 注解来清除 Redis 缓存中的数据。以下是一个使用 @CacheEvict 注解的示例:

@Servicepublic class UserService {@Cacheable(value = "users", key = "#id")public User getUserById(Long id) {// 查询用户并返回}@CacheEvict(value = "users", key = "#id")public void deleteUserById(Long id) {// 删除用户并返回}@CacheEvict(value = "users", allEntries = true)public void deleteAllUsers() {// 删除所有用户并返回}
}

在此示例中,我们添加了删除单个用户和删除所有用户的两个方法,使用 @CacheEvict 注解来删除Redis 缓存中的相应数据。请注意,我们设置了 allEntries 属性为 true,以删除所有缓存中的数据。

3.5 yml配置

spring:cache:type: redisredis:cache-names: userCache,providerCache #缓存名称列表cache-null-values: false #查询结果为 null 不进行缓存time-to-live: 90000ms #缓存毫秒 设置过期时间use-key-prefix: true #配置key的前缀 如果指定了前缀,就用指定的,如果没有,就默认使用缓存的名字作为前缀

下面90秒后消失。
在这里插入图片描述

3.6 缓存管理

上面的3.5yml配置的方式有问题,我们所有的@Cacheable(cacheNames = "userCache", key = "#id")都是90秒。我们希望在写@Cacheable是自定义缓存时间。即最终我们期望的使用方式如下。

@Cacheable(cacheNames = "demoCache#3600", key = "#id")

通过 # 分隔,后面部分表示此 Cache 的TTL(单位:秒)
下面来写代码演示

演示之前记得把yml中的配置删除。

3.6.1 编写MyRedisCacheManager配置类

编写MyRedisCacheManager 类,给下面的CacheConfig类中的cacheManager方法使用。MyRedisCacheManager这个类只是把字符串中的时间给拆了出来。

package com.hsh.config;public class MyRedisCacheManager extends RedisCacheManager {public MyRedisCacheManager(RedisCacheWriter cacheWriter,RedisCacheConfiguration defaultCacheConfiguration) {super(cacheWriter, defaultCacheConfiguration);}@Overrideprotected RedisCache createRedisCache(String name, RedisCacheConfigurationcacheConfig) {String[] array = StringUtils.delimitedListToStringArray(name, "#");name = array[0];if (array.length > 1) { // 解析TTLlong ttl = Long.parseLong(array[1]);cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); // 注意单位我此处用的是秒,而非毫秒}return super.createRedisCache(name, cacheConfig);}
}

3.6.2 编写CacheConfig

package com.hsh.config;
// @EnableCaching已经在启动类配置过这里不用配置了。
//@EnableCaching // 使用了CacheManager,别忘了开启它 否则无效
@Configuration
public class CacheConfig extends CachingConfigurerSupport {@Beanpublic CacheManager cacheManager() {// entryTtl(Duration.ofDays(1))是今天有效RedisCacheConfiguration defaultCacheConfig =RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)).computePrefixWith(cacheName -> "caching:" + cacheName);MyRedisCacheManager redisCacheManager = new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory()), defaultCacheConfig);return redisCacheManager;}@Beanpublic RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration configuration = newRedisStandaloneConfiguration();configuration.setHostName("127.0.0.1");configuration.setPort(6379);configuration.setDatabase(0);configuration.setPassword("123456");LettuceConnectionFactory factory = newLettuceConnectionFactory(configuration);return factory;}// 下面这个序列化可以不写,因为我们已经在RedisConfig这个类中配置过了序列化//@Bean//public RedisTemplate<String, String> redisTemplate() {//    RedisTemplate<String, String> redisTemplate = new StringRedisTemplate();//    redisTemplate.setConnectionFactory(redisConnectionFactory());//    return redisTemplate;//}
}

3.6.3 演示

package com.hsh.service.impl;@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate UserMapper userMapper;// 注意这里必须使用@Cacheable的属性cacheNames 且我们设置的单位是秒。@Override@Cacheable(cacheNames = "userCache#30", key = "#id")public ResultJSON<User> getUserById(Long id) {User user = userMapper.selectById(id);return ResultJSON.success(user);}
}

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

B站 韩顺平 笔记 (Day 29)

目录 1&#xff08;集合的框架体系&#xff09; 2&#xff08;Collection接口和常用方法&#xff09; 2.1&#xff08;Collection接口实现类特点&#xff09; 2.2&#xff08;常用方法&#xff09; 2.3&#xff08;遍历元素方式1&#xff1a;迭代器&#xff09; 1&#x…

axios报错解决:unsupported BodyInit type

目录 问题 原因 解决方法 问题 Got ‘unsupported BodyInit type’ bug on iPhone 14(IOS 17.5) Issue #6444 axios/axios 我这里是iPhone 6plus打开会报错白屏 好多人遇到了相同的问题 当我在 iPhone 14 上浏览页面时,我收到一条错误消息:错误:不支持的 BodyInit 类型,…

iperf3网络性能测试工具

iperf3 是一个功能非常强大的网络性能测试工具,用于测量两个网络节点之间的最大TCP、UDP带宽和性能。它通过创建数据流并测量其吞吐量来工作。 下面我将为您详细介绍其核心用法、常用命令和参数。 核心概念:客户端/服务器模式 iperf3 测试需要两台机器:一台作为服务器端(…

【C#】 资源共享和实例管理:静态类,Lazy<T>单例模式,IOC容器Singleton我们该如何选

文章目录前言一、静态类1.1 静态类的特点1.2 静态类的使用1.3 静态类的缺点二、单例模式2.1 Lazy延迟初始化2.2 Lazy< T>单例模式的使用2.3 单例模式的特点三、IOC的Singleton总结前言 编写程序的时候&#xff0c;常常能碰到当某些数据或方法需要被整个程序共享&#xf…

MySQL——存储引擎、索引

一、存储引擎1.MySQL体系结构2.存储引擎简介存储引擎就是储存数据、建立索引、更新/查询数据等技术的实现方式。储存引擎是基于表的&#xff0c;而不是基于库的&#xff0c;所以存储引擎也可被称为表类型建表语句&#xff1a;查询数据库支持的储存引擎&#xff1a;show engines…

机器学习01——机器学习概述

上一章&#xff1a;机器学习核心知识点目录 下一章&#xff1a;机器学习02——模型评估与选择 机器学习实战项目&#xff1a;【从 0 到 1 落地】机器学习实操项目目录&#xff1a;覆盖入门到进阶&#xff0c;大学生就业 / 竞赛必备 文章目录一、参考书推荐二、机器学习的基本概…

Shell编程:检测主机ip所在网段内其他在线ip

一、逻辑设计获取本机 ip 及 网段循环检测网段内所有 ip判断 ping 结果&#xff0c;符合条件的输出相关信息二、代码展示#!/bin/bash#获取本机ip local_iphostname -I #local_ipip addr| grep "inet "|grep -v 127.0.0.1| awk {print $2}#获取本机网段 networkecho $…

Windows安装Chroma DB

安装步骤 安装python 3.8或以上的版本创建虚拟环境&#xff1a;python -m venv chroma_env激活虚拟环境&#xff1a;.\chroma_env\Scripts\activate安装Chroma DB&#xff1a;pip install chromadb(可选)安装扩展功能&#xff1a;pip install sentence-transformers pypdf tikt…

李彦宏亲自说

昨天&#xff0c;李彦宏亲自说&#xff1a;百度的数字人直播以假乱真&#xff0c;很多人是看不出这是数字人&#xff0c;而且转化率很高”这几个月百度一直在推“数字人”不再强调“大模型”了。数字人是AI落地最适合企业的一款产品&#xff0c;一般用于客服、面试、直播带货等…

JS 中bind、call、apply的区别以及手写bind

1.作用call、apply、bind作用是改变函数执行的上下文&#xff0c;简而言之就是改变函数运行时的this指向那么什么情况下需要改变this的指向呢&#xff1f;下面举个例子var name "lucy"; var obj {name: "martin",say: function () {console.log(this.nam…

vue2(7)-单页应用程序路由

1.单页应用程序如 单页&#xff1a;网易云&#xff0c;多页&#xff1a;京东单页应用程序&#xff0c;之所以开发效率高&#xff0c;性能高&#xff0c;用户体验好最大的原因是&#xff1a;页面按需更新 要按需更新&#xff0c;就要明确访问路径和组件的关系这时候就要用…

vue中通过heatmap.js实现热力图(多个热力点)热区展示(带鼠标移入弹窗)

直接上完整代码&#xff01;记录实现方式 注意heatmap.min.js需要通过heatmap.js提供的下载地址进行下载&#xff0c;地址放在下边 url&#xff1a;heatmap GIT地址 <template><div class"heatmap-view" ref"heatmapContainer"></div&g…

配置Kronos:k线金融大模型

github地址 网页btc预测demo使用的Kronos-mini模型 huggingface的仓库 文章目录配置环境安装python环境获取市场数据的库通过webui使用example中的例子prediction_example.py补充说明根据原例优化的代码CryptoDataFetcher单币对多周期预测配置环境 使用conda的环境. 首先进行换…

【Deep Learning】Ubuntu配置深度学习环境

【start: 250715】 文章目录ubuntu与深度学习安装cuda查看显卡信息&#xff08;nvidia-smi&#xff09;升级驱动下载cuda安装conda安装anaconda默认指向自己的conda初始化conda确认 conda.sh 被加载安装cuda-toolkit直接安装cuda-toolkit&#xff08;高级的&#xff09;安装高于…

车载数据采集(DAQ)解析

<摘要> 车载数据采集&#xff08;DAQ&#xff09;软件模块是现代汽车电子系统的核心组件&#xff0c;负责实时采集、处理、记录和传输车辆运行数据。本文系统解析了DAQ模块的开发&#xff0c;涵盖其随着汽车智能化演进的历史背景&#xff0c;深入阐释了信号、协议、缓存等…

强化学习框架Verl运行在单块Tesla P40 GPU配置策略及避坑指南

1.前言 由于比较穷,身边只有1块10年前的Tesla P40 GPU卡(2016年9月发布),想利用起来学习强化学习框架Verl。程序员学习开源代码,大部分人的第一直觉不是分析模块组成,而是跑起来试试,然后去debug一下后面的运行逻辑。 由于在官方部署指导文档中并未指明跑通Verl的最低…

leetcode169.多数元素

题目描述给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。题目解法博耶-摩尔多数投票算法&#xff08;英语&#xff1a;Boyer–Moore…

基于机器学习的P2P网贷平台信用违约预测模型

使用平台提供的借款人信息&#xff08;年龄、收入、历史信用等&#xff09;和借款信息&#xff0c;构建一个二分类模型来预测借款人是否会违约。重点解决类别不平衡问题和模型可解释性。逻辑回归、随机森林、XGBoost、SMOTE过采样、模型评估&#xff08;AUC, KS, F1-Score&…

豆瓣网影视数据分析与应用

源码链接&#xff1a;点击下载源码 相关文档&#xff1a;点击下载相关文档 摘 要 随着互联网的快速发展&#xff0c;豆瓣网作为一个综合性的影视评分和评论平台&#xff0c;积累了大量的用户数据&#xff0c;这些数据为影视分析提供了丰富的素材。借助Hadoop这一大数据处理框…

四、计算机网络与分布式系统(中)

一、局域网与广域网1、局域网&#xff08;1&#xff09;定义将有限地理范围内的多台计算机通过传输媒体连接&#xff0c;借助网络软件实现设备间通信与资源共享的通信网络&#xff08;2&#xff09;特点1.地理范围小&#xff1a;通常为数百米至数公里内。2.传输速率高&#xff…