ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringCache的基本使用

2022-08-31 17:01:41  阅读:156  来源: 互联网

标签:基本 缓存 SpringCache value user key 使用 userCache id


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 的

@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 相反.
     *
     *  注意: Cacheable 的 condition属性,其 SpEL 是没有 result的
     * @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;
    }
}

标签:基本,缓存,SpringCache,value,user,key,使用,userCache,id
来源: https://www.cnblogs.com/gzyup/p/16642510.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有