SpringBoot结合Redis实现缓存管理功能

 更新时间:2024年01月29日 11:51:45   作者:棒棒糖_  
本篇文章主要介绍spring boot缓存管理机制及相关概念,以及如何结合Redis实现缓存管理,文中通过代码示例给大家介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下

一、概述

目标:

  • 熟悉Spring Cache基础组件及作用
  • 熟悉Spring Cache常用注解及作用
  • 掌握SpringBoot结合Redis实现缓存管理

二、 Spring Cache基础组件

  • keyGenerator

    keyGenerator 是用于生成缓存键(Cache Key)的组件。缓存键是用于在缓存中唯一标识缓存数据的值。默认情况下,Spring Cache 使用参数列表作为缓存键。但在某些情况下,如果需要自定义缓存键的生成逻辑,则可以创建自定义的 KeyGenerator 实现并配置到 Spring 中,如果没有自定义的话Spring提供默认的keyGenerator——SimplekeyGenerator,它会根据方法参数列表生成一个唯一的缓存 key。

  • cacheManager

    在 Spring Cache 框架中,CacheManager 是用于管理缓存实例的组件。它可以创建和管理多个缓存,每个缓存都有一个唯一的名称。当开发者在项目中配置了 Redis(或其他支持的缓存中间件),Spring 会自动使用相应的 CacheManager 实现,如 RedisCacheManager。 如果没有配置任何缓存中间件,Spring 默认会采用 SimpleCacheManager 作为缓存管理器。SimpleCacheManager 内部使用 ConcurrentHashMap 来维护缓存数据,它是一个线程安全的 HashMap 实现。这种情况下,并不需要额外的缓存中间件,Spring 会将缓存数据存储在内存中。

  • cacheResolver 和cacheManager作用一样,使用时二选一

三、 缓存管理注解

  • @EnableCaching

    该注解用于启用 Spring Framework 的缓存支持。通常在配置类上使用,表示开启缓存机制。有一个可选参数 proxyTargetClass,默认值为 false,表示使用 JDK 动态代理实现 AOP,如果设置为 true,则表示使用 CGLIB 代理进行 AOP。

  • @CacheConfig

    @CacheConfig 注解用于配置缓存的公共属性,如缓存名称、缓存管理器等。可以在类级别上使用,表示该类中的所有方法都具有相同的缓存规则。 该注解可选参数:

    • cacheNames:指定缓存名称。
    • keyGenerator:指定缓存 key 生成策略。
    • cacheManager:指定缓存管理器。
  • @CacheAble

    @Cacheable 注解用于标注方法的返回值可以被缓存,通常用于查询操作。如果缓存中存在对应的数据,则直接从缓存中获取数据返回,否则执行方法并将返回值存入缓存中。该注解可选参数:

    • cacheNames:指定缓存名称。

    • key:指定缓存 key,需要使用 SpEL 表达式进行动态计算,没有指定的话,会使用keyGenerator

      • cacheNamekey 可以组合成最终用于在 Redis 等缓存中存储数据的 key。通常情况下,cacheName 代表缓存的名称,而 key 则用于标识缓存中的具体数据。当使用 @Cacheable(cacheNames = "myCache", key = "#user.id") 这样的注解时,Spring 将会根据给定的 cacheNamekey 生成一个唯一的缓存 key,然后将方法返回的数据缓存到 Redis 中。
      • 例如,在 Redis 中可能会生成类似于 myCache::123 这样的键来存储缓存数据,其中 myCache 是缓存名称,123 则是根据 #user.id 表达式计算得出的具体键值。
    • condition:指定一个 SpEL 表达式,当条件为 true 时才会进行缓存操作。

    • unless:指定一个 SpEL 表达式,当条件为 false 时才会进行缓存操作。

      • condition属性是在方法执行前计算的,因此无法获取到方法返回结果。unless属性是在方法执行后计算的,因此可以拿到方法返回结果,即SpEL 表达式中可以使用#result获取到方法返回值。
    • sync:指定缓存是否需要同步更新。默认情况下,Spring Cache 不会对缓存进行同步更新,即在多线程环境下可能会出现缓存不一致的问题。但是,如果我们希望在缓存更新时进行同步操作,可以使用 sync 属性来实现。

//当方法被多个线程并发调用时,只有一个线程能够执行方法并更新缓存,其他线程会被阻塞,直到更新完成后才能继续执行。
@Cacheable(cacheNames = "myCache", key = "#id", sync = true)
public User getUserById(Long id) {
    //....
}
//注意:使用 `sync` 属性会增加缓存访问的时间和资源消耗,因此建议只在必要的情况下使用。另外,对于高并发场景,使用 `sync` 属性可能会导致性能问题,因此需要谨慎使用。
  • 以下是常用的 SpEL 表达式及其说明:

    表达式说明
    #root代表被调用方法的参数列表
    #root.target代表被调用方法的目标对象
    #root.caches代表方法调用对应的缓存
    #root.methodName代表被调用方法的名称
    #root.targetClass代表被调用方法所在的类
    #result代表方法调用的返回结果(仅在 @Cacheable 和 @CachePut 注解中有效)
    #argument代表方法的参数,例如 #a0 代表第一个参数,#p0 也代表第一个参数
    T(...)调用静态方法,比如 T(java.lang.Math).PI
    方法调用直接调用方法,比如 hasPermission('read')
    集合访问访问数组、列表、集合等元素,比如 list[0]
    属性访问访问对象的属性,比如 [user.name]
  • @CachePut

    @CachePut 注解用于缓存标注方法的返回值,不管缓存中是否存在相同的键值,通常用于增加或更新操作。在方法执行后,将执行结果缓存到指定的缓存中。

    该注解可选参数:

    • cacheNames:同@Cacheable
    • key:同@Cacheable
    • condition: 同@Cacheable
    • unless:同@Cacheable
  • @CacheEvict

    @CacheEvict 注解用于标注方法执行后删除缓存中的数据,通常用于删除操作。

    该注解可选参数:

    • cacheNames:同@Cacheable
    • key:同@Cacheable
    • condition:同@Cacheable
    • allEntries:配合cacheNames一起使用,当 allEntries 属性设置为 true 时,表示清除缓存中缓存名称为cacheNames的所有条目。allEntries 默认值为false,表示只删除与该方法对应的缓存条目。
      • 例如:@CacheEvict(cacheNames = "k1",allEntries = true),会删除缓存中所有缓存名称为k1的键值对。
    • beforeInvocation:当 beforeInvocation 属性设置为 true 时,表示在方法执行之前清除缓存;即使方法执行出现异常,缓存仍然会被清除。当 beforeInvocation 属性设置为 false (默认值)时,表示在方法执行之后清除缓存;如果方法执行出现异常,缓存不会被清除。

四、 代码示例

添加pom依赖

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

数据缓存

@Service
@CacheConfig(cacheNames = "user")
public class CacheService {

    @CachePut(key = "'userId:' + #p0.userId")
    public User addUser(User user){
        System.out.println("添加成功:user = " + user);
        return user;
    }

    @Cacheable(key = "'userId:' + #p0")
    public User getUser(Integer userId){
        User userFromDB = getUserFromDB(userId);
        System.out.println("查询成功: userId = " + userId);
        return userFromDB;
    }

    @CachePut(key = "'userId:' + #p0")
    public User update(Integer userId,User user){
        updateUserInDB(userId,user);
        System.out.println("更新成功:userId = " + userId);
        return user;
    }

    private void updateUserInDB(Integer userId,User user) {
        user.setUsername("DB_user");
    }

    private User getUserFromDB(Integer userId) {
        User user = new User();
        user.setUserId(userId);
        user.setUsername("DB_user");
        return user;
    }

    @CacheEvict(cacheNames = "k1",allEntries = true)
    public void del(int id){
    }
}

单元测试

@SpringBootTest
public class CacheServiceTest {
    @Resource
    private CacheService cacheService;
    private User user;

    @BeforeEach
    void initUser(){
        user = new User();
        user.setUserId(1);
        user.setUsername("zhang san");
        user.setNickname("xiao san");
        user.setPhone("18788888888");
    }

    @Test
    void addCacheTest(){
        cacheService.addUser(user);
    }
    @Test
    void getCacheTest(){
        User user = cacheService.getUser(1);
        System.out.println("user = " + user);
    }

    @Test
    void updateCacheTest(){
        cacheService.update(1,user);
    }

    @Test
    void delCacheTest(){
        cacheService.del(2);
    }

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void key() {
        // 这里将缓存key都捞出来
        Set<String> keys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<byte[]> sets = connection.keys("k*".getBytes());
            Set<String> ans = new HashSet<>();
            assert sets != null;
            for (byte[] b : sets) {
                ans.add(new String(b));
            }
            return ans;
        });
        System.out.println("keys = " + keys);
    }
}

总结

以上就是SpringBoot结合Redis实现缓存管理功能的详细内容,更多关于SpringBoot Redis缓存管理的资料请关注脚本之家其它相关文章!

相关文章

  • 图文详解java内存回收机制

    图文详解java内存回收机制

    这篇文章主要以图文结合的方式为大家详细介绍了java内存回收机制,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • SpringBoot注入Bean的四种方式总结

    SpringBoot注入Bean的四种方式总结

    这篇文章主要给大家总结SpringBoot注入Bean的四种方式,启动类注入Bean,启动类扫描@ComponentScan,启动类@EnableConfigurationProperties以及启动类@Import这四种方式,文章通过代码示例讲解非常详细,需要的朋友可以参考下
    2023-11-11
  • 一文详解Java中Map和Set接口的使用方法

    一文详解Java中Map和Set接口的使用方法

    Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关,可能在查找时进行一些插入和删除的操作,即动态查找,那上述两种方式就不太适合了,本节介绍的Map和Set是一种适合动态查找的集合容器,需要的朋友可以参考下
    2024-08-08
  • 使用注解@Validated效验VO参数是否合规

    使用注解@Validated效验VO参数是否合规

    这篇文章主要为大家介绍了使用注解@Validated效验VO参数是否合规过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • servlet实现文件下载的步骤及说明详解

    servlet实现文件下载的步骤及说明详解

    这篇文章主要为大家详细介绍了servlet实现文件下载的步骤及说明,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • 浅谈JVM内存溢出原因和解决思路

    浅谈JVM内存溢出原因和解决思路

    本文主要介绍了浅谈JVM内存溢出原因和解决思路,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Spring Cloud Config与Bus整合实现微服务配置自动刷新功能

    Spring Cloud Config与Bus整合实现微服务配置自动刷新功能

    通过整合SpringCloud Config与Spring Cloud Bus,实现了微服务配置的自动刷新功能,这个机制允许一个微服务实例在配置更新时通过消息总线通知其他所有实例同步更新,从而保持配置的一致性并提升系统的运维效率
    2024-10-10
  • SpringBoot校园综合管理系统实现流程分步讲解

    SpringBoot校园综合管理系统实现流程分步讲解

    这篇文章主要介绍了SpringBoot+Vue实现校园综合管理系统流程分步讲解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-09-09
  • Apache Commons Math3学习之数值积分实例代码

    Apache Commons Math3学习之数值积分实例代码

    这篇文章主要介绍了Apache Commons Math3学习之数值积分实例代码,涉及使用辛普森积分的例子,这里分享给大家,供需要的朋友参考。
    2017-10-10
  • SpringBoot如何基于POI-tl和word模板导出庞大的Word文件

    SpringBoot如何基于POI-tl和word模板导出庞大的Word文件

    这篇文章主要介绍了SpringBoot如何基于POI-tl和word模板导出庞大的Word文件,poi-tl是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库
    2022-08-08

最新评论