SpringCache的基本使用
SpringCache
SpringCache是一个框架,实现了基于注解的缓存功能。SpringCache提供了一层抽象,底层可以切换不同的cache实现。具体是通过CacheManager接口来统一不同的缓存技术.
CacheManager是Spring提供的各种缓存技术抽象接口.
针对不同的缓存技术需要实现不同的CacheManager:
| CacheManmager | 描述 | |
|---|---|---|
| EhCacheCacheManager | 使用EhCache作为缓存技术 | |
| GuavaCacheManager | 使用Google的GuavaCache作为缓存技术 | |
| RedisCacheManager | 使用Redis作为缓存技术 | |
| ...... ...... | ||
| 使用Map也可以实现缓存 |
SpringCache常用注解
| 注解 | 说明 | |
|---|---|---|
| @EnableCaching | 开启缓存注解功能 | |
| @CachePut | 在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据; 如果没有数据,调用方法并将方法返回值放到缓存中 | |
| @CacheEvict | 将一条或多条数据从缓存中删除 |
@SpringBoot项目中,使用缓存技术只需要在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存技术即可.
底层使用Map来实现缓存
首先导入相应的依赖
<!-- 导入这个就可以使用 SpringCache的基础功能了,因为相关依赖也被导入了,
这里暂时使用 Map来实现缓存,如果使用 Redis还需要导入Redis相关的依赖
spring-boot-starter-cache
很多基本的API都在 spring-context 上下文依赖中.
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
启动类上开启缓存注解
@Slf4j
@SpringBootApplication
@EnableCaching // 开启缓存 基础的 API都在 spring-context jar包中 上下文 jar包.
public class CacheDemoApplication {
public static void main(String[] args) {
SpringApplication.run(CacheDemoApplication.class,args);
log.info("项目启动成功...");
}
}
先看一下,此时提供的对CacheManager默认的实现

默认是提供了这五个实现

此案例使用的是 ConcurrentMapCacheManager

使用ConcurrentMap来实现缓存,也就是使用 Map 来实现缓存
controller层的练习案例
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private CacheManager cacheManager; // 统一不同的缓存技术 默认用的是 ConcurrentMapManager,ConcurrentMap缓存数据
@Autowired
private UserService userService;
/**
* CachePut 将方法的返回值放入缓存中
* 底层使用什么缓存产品,就看当前配置的缓存。这个案例中使用的最基础的环境,使用的是 Map来实现的缓存.
* value: 缓存的名称
* key: 缓存的 key 一般不写死,key的值应该是动态的. key支持 SpEL Spring表达式语言,可以动态地计算 key值. #表达式
* #result 代表方法的返回值
* #root 代表当前的方法 root.method root.methodName root.targetClass root.caches
* 获取方法参数 #user,user就是形参变量,注意名字要一样 #user.name #user.id
* 还可以这样获取参数,#root.args[index],下标从 0开始.
* 或者这样 #pindex p是固定写法,后面跟下标. #p1 #p0
* 每个缓存名称下面可以有多个 key
*
* 这个 Map是基于内存的,服务重启之后,缓存中的数据就没有了.
* @param user 用户对象
* @return 保存的用户对象数据
*/
@CachePut(value = "userCache", key = "#result.id") // 把插入的数据放到缓存中,需要指定 value,value 代表缓存的名称, key代表缓存的 key.
@PostMapping // value 是 一类缓存;具体这个分类下面可能会有多个缓存数据,多个缓存数据就需要根据 key来进行区分.
public User save(User user){
userService.save(user);
return user;
}
/**
* CacheEvict 清理指定缓存
* value
* key
* 具体哪个缓存,由 value 和 key 来指定. 唯一锁定缓存数据.
* @param id
*/
// @CacheEvict(value = "userCache", key = "#p0")
// @CacheEvict(value = "userCache", key = "#root.args[0]")
@CacheEvict(value = "userCache", key = "#id") // 注意,这个名字要和参数名保持一致,这样可以获取参数变量
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
// @CacheEvict(value = "userCache", key = "#p0.id")
// @CacheEvict(value = "userCache", key = "#user.id")
// @CacheEvict(value = "userCache", key = "#root.args[0].id")
@CacheEvict(value = "userCache", key = "#result.id") // 从返回结果中获取.
@PutMapping
public User update(User user){
userService.updateById(user);
return user;
}
/**
* Cacheable 若缓存中有数据,直接在缓存中拿; 如果没有,先从数据库中查出,然后再放入缓存中
* value
* key
* condition: 条件,满足条件时才会缓存数据
* unless: 满足这个条件时,不会缓存数据, 和 condition 相反.
* @param id id
* @return 查询结果
*/
@Cacheable(value = "userCache", key = "#id", condition = "#result != null") // 如果有缓存,则直接从缓存中拿数据. 没有的话先从数据库中取,然后再放入缓存.
@GetMapping("/{id}") // 查不存在的数据,返回为空,也会给缓存上. id 为 key,value 为 null 缓存
public User getById(@PathVariable Long id){ // 如何配置,value 不为空时才会缓存呢? 使用 condition属性或者 unless属性
User user = userService.getById(id);
return user;
}
@Cacheable(value = "userCache", key = "#user.id + '_' + #user.name") // 不同的查询条件分别对应不同的缓存数据.
@GetMapping("/list")
public List<User> list(User user){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(user.getId() != null,User::getId,user.getId());
queryWrapper.eq(user.getName() != null,User::getName,user.getName());
List<User> list = userService.list(queryWrapper);
return list;
}
}
底层使用Redis来实现缓存技术
引入依赖
<!-- SpringCache使用Redis实现缓存技术
spring-boot-starter-cache 扩展了一些对缓存技术的整合
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Redis的 cacheManager RedisCacheManager
在这个依赖中.
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
引入 spring-boot-starter-cache 后,看一下底层对 CacheManager 的实现扩展了哪些

这里扩展了很多实现,但是没有 Redis 的 cacheManager,那么需要再引入 spring-boot-starter-data-redis 依赖才可以,引入后再观察

可以看到有了关于 RedisCacheManager 的实现.
相关配置文件中的配置
spring:
# redis 配置
redis:
host: your ip
port: your port
password: your password
database: 0
# 设置缓存有效期
cache:
redis:
time-to-live: 1800000 #单位毫秒,30min
那么此时底层就换成了redis来实现缓存技术了,用法都是一样的
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.entity.User;
import com.itheima.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@Autowired
private CacheManager cacheManager; // 统一不同的缓存技术 默认用的是 ConcurrentMapManager,ConcurrentMap缓存数据
@Autowired
private UserService userService;
/**
* CachePut 将方法的返回值放入缓存中
* 底层使用什么缓存产品,就看当前配置的缓存。这个案例中使用的最基础的环境,使用的是 Map来实现的缓存.
* value: 缓存的名称
* key: 缓存的 key 一般不写死,key的值应该是动态的. key支持 SpEL Spring表达式语言,可以动态地计算 key值. #表达式
* #result 代表方法的返回值
* #root 代表当前的方法 root.method root.methodName root.targetClass root.caches
* 获取方法参数 #user,user就是形参变量,注意名字要一样 #user.name #user.id
* 还可以这样获取参数,#root.args[index],下标从 0开始.
* 或者这样 #pindex p是固定写法,后面跟下标. #p1 #p0
* 每个缓存名称下面可以有多个 key
*
* 这个 Map是基于内存的,服务重启之后,缓存中的数据就没有了.
* @param user 用户对象
* @return 保存的用户对象数据
*/
@CachePut(value = "userCache", key = "#result.id") // 把插入的数据放到缓存中,需要指定 value,value 代表缓存的名称, key代表缓存的 key.
@PostMapping // value 是 一类缓存;具体这个分类下面可能会有多个缓存数据,多个缓存数据就需要根据 key来进行区分.
public User save(User user){
userService.save(user);
return user;
}
/**
* CacheEvict 清理指定缓存
* value
* key
* 具体哪个缓存,由 value 和 key 来指定. 唯一锁定缓存数据.
* @param id
*/
// @CacheEvict(value = "userCache", key = "#p0")
// @CacheEvict(value = "userCache", key = "#root.args[0]")
@CacheEvict(value = "userCache", key = "#id") // 注意,这个名字要和参数名保持一致,这样可以获取参数变量
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
// @CacheEvict(value = "userCache", key = "#p0.id")
// @CacheEvict(value = "userCache", key = "#user.id")
// @CacheEvict(value = "userCache", key = "#root.args[0].id")
@CacheEvict(value = "userCache", key = "#result.id") // 从返回结果中获取.
@PutMapping
public User update(User user){
userService.updateById(user);
return user;
}
/**
* Cacheable 若缓存中有数据,直接在缓存中拿; 如果没有,先从数据库中查出,然后再放入缓存中
* value
* key
* condition: 条件,满足条件时才会缓存数据
* unless: 满足这个条件时,不会缓存数据, 和 condition 相反.
* @param id id
* @return 查询结果
*/
// @Cacheable(value = "userCache", key = "#id", condition = "#result != null") // 如果有缓存,则直接从缓存中拿数据. 没有的话先从数据库中取,然后再放入缓存.
@Cacheable(value = "userCache", key = "#id", unless = "#result == null") // 换成了 redis,redis的 condition中是不能使用 result返回结果的.
@GetMapping("/{id}") // 查不存在的数据,返回为空,也会给缓存上. id 为 key,value 为 null 缓存
public User getById(@PathVariable Long id){ // 如何配置,value 不为空时才会缓存呢? 使用 condition属性或者 unless属性
User user = userService.getById(id);
return user;
}
@Cacheable(value = "userCache", key = "#user.id + '_' + #user.name") // 不同的查询条件分别对应不同的缓存数据.
@GetMapping("/list")
public List<User> list(User user){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(user.getId() != null,User::getId,user.getId());
queryWrapper.eq(user.getName() != null,User::getName,user.getName());
List<User> list = userService.list(queryWrapper);
return list;
}
}
注意: Cacheable 的 condition属性,其 SpEL 是没有 result的

而 unless属性是可以使用 result 的

SpringCache的基本使用的更多相关文章
- SpringCache缓存初探
body,table tr { background-color: #fff } table tr td,table tr th { border: 1px solid #ccc; text-alig ...
- SpringCache与redis集成,优雅的缓存解决方案
缓存可以说是加速服务响应速度的一种非常有效并且简单的方式.在缓存领域,有很多知名的框架,如EhCache .Guava.HazelCast等.Redis作为key-value型数据库,由于他的这一特性 ...
- SpringCache @Cacheable 在同一个类中调用方法,导致缓存不生效的问题及解决办法
由于项目需要使用SpringCache来做一点缓存,但自己之前没有使用过(其实是没有听过)SpringCache,于是,必须先学习之. 在网上找到一篇文章,比较好,就先学习了,地址是: https:/ ...
- SpringCache学习之操作redis
一.redis快速入门 1.redis简介 在java领域,常见的四大缓存分别是ehcache,memcached,redis,guava-cache,其中redis与其他类型缓存相比,有着得天独厚的 ...
- SpringBoot基础系列-SpringCache使用
原创文章,转载请标注出处:<SpringBoot基础系列-SpringCache使用> 一.概述 SpringCache本身是一个缓存体系的抽象实现,并没有具体的缓存能力,要使用Sprin ...
- spring-boot的spring-cache中的扩展redis缓存的ttl和key名
原文地址:spring-boot的spring-cache中的扩展redis缓存的ttl和key名 前提 spring-cache大家都用过,其中使用redis-cache大家也用过,至于如何使用怎么 ...
- SpringCache实战遇坑
1. SpringCache实战遇坑 1.1. pom 主要是以下两个 <dependency> <groupId>org.springframework.boot</g ...
- SpringCache学习实践
1. SpringCache学习实践 1.1. 引用 <dependency> <groupId>org.springframework.boot</groupId> ...
- SpringBoot2.X + SpringCache + redis解决乱码问题
环境:SpringBoot2.X + SpringCache + Redis Spring boot默认使用的是SimpleCacheConfiguration,使用ConcurrentMapCach ...
- AOP方法增强自身内部方法调用无效 SpringCache 例子
开启注解@EnableCaChing,配置CacheManager,结合注解@Cacheable,@CacheEvit,@CachePut对数据进行缓存操作 缺点:内部调用,非Public方法上使用注 ...
随机推荐
- Aeraki Mesh正式成为CNCF沙箱项目,腾讯云携伙伴加速服务网格成熟商用
6月,由腾讯云主导,联合百度.灵雀云.腾讯音乐.滴滴.政采云等多家合作伙伴发起的服务网格开源项目 Aeraki Mesh 通过了全球顶级开源基金会云原生计算基金会(CNCF)技术监督委员会评定,正式成 ...
- mysql InnoDB通过.frm和.ibd恢复表和数据
ibdata1是一个用来构建innodb系统表空间的文件,这个文件包含了innodb表的元数据.撤销记录.修改buffer和双写buffer.如果file-per-table选项打开的话,该文件则不一 ...
- Oracle创建用户和表空间
一.概述 1.数据库实际管理中,不同业务系统需要使用'不同的用户'进行管理维护和使用,这样做把业务数据和系统数据独立分开管理,利于数据库系统管理: 2.在数据库中创建业务系统用户时候,建议为用户创建指 ...
- Oracle数据库控制文件多路复用
Oracle数据库控制文件多路复用多路复用控制文件,指的是在系统不同的位置上同时存放多个控制文件的副本,此时如果某个路径对应的磁盘发送物理损坏导致该控制文件损坏,就可以通过另一个磁盘上的控制文件进行恢 ...
- 攻防世界MISC—进阶区1-10
1.something_in_image zip中的文件用010 Editor打开后直接搜索flag,即可找到flag 2.wireshark-1 zip内是pcap文件,打开后根据题目知道要寻找登录 ...
- ClickHouse(04)如何搭建ClickHouse集群
ClickHouse集群的搭建和部署和单机的部署是类似的,主要在于配置的不一致,如果需要了解ClickHouse单机的安装设部署,可以看看这篇文章,ClickHouse(03)ClickHouse怎么 ...
- 意想不到的Python ttkbootstrap 制作账户注册信息界面
嗨害大家好,我是小熊猫 今天给大家来整一个旧活~ 前言 ttkbootstrap 是一个基于 tkinter 的界面美化库,使用这个工具可以开发出类似前端 bootstrap 风格的tkinter 桌 ...
- web 前端 基础HTML知识点
web系统架构体系 B/S(Browser/Server):浏览器实现 优点: 规范.使用方便.本身实现成本低 容易升级.便于维护 缺点: 没有网络,无法使用 保存数据量有限,和服务器交互频率高.耗费 ...
- Identity Server 4使用OpenID Connect添加用户身份验证(三)
一.说明 基于上一篇文章中的代码进行继续延伸,只需要小小的改动即可,不明白的地方可以先看看本人上一篇文章及源码: Identity Server 4资源拥有者密码认证控制访问API(二) GitHub ...
- Scala的基础用法 和 Java相对应学习(二)变量、循环、语法
一.配置相关环境 1.增加项目 在idea里面创建新的maven项目 2. 在pom文件中增加依赖 <?xml version="1.0" encoding="UT ...