Springboot——整合Redis

本文介绍了如何在Spring Boot中配置并使用Redis进行数据缓存,包括引入Jedis依赖、创建RedisConfig配置文件以设置序列化方式和过期时间,以及在Controller中使用@Cacheable注解实现缓存功能。此外,还探讨了Redis的简单事务处理,并分析了@Cacheable注解可能失效的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、核心流程

  1. 引入依赖
  2. 创建RedisConfig配置文件
  3. 使用Redis缓存数据

配置Redis的序列化是为了解决程序中的数据转化成Redis二进制数据后无法直观查看数据信息的问题。

二、代码实战

2.1 引入依赖

spring-boot-starter-data-redis默认会使用lettuce,本次使用的是Jedis,所以依赖中我们要屏蔽掉lettuce而改用jedis。

Springboot会帮我们自动装配Redis,自动生成RedisConnectionFactory、RedisTemplate、StringRedisTemplate等常用的Redis对象。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.7.5</version>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

在spring-data-redis中,RedisConnection通过RedisConnectionFactory创建,Spring为了简化以上操作,做出了简化,并诞生了RedisTemplate

2.2 创建RedisConfig配置文件

因为Redis的数据以二进制的方式存储,与Java数据不相同,所以直接存入Java数据到Redis中会导致你在使用RedisCli查看数据时,是我们无法看懂的二进制序列化数据,为了解决这个问题,我们需要对Redis配置序列化的方式。

package com.example.demo.config.redis;
/**
 * @Author : HuangJiajian
 * @create 2022/10/24 9:07
 */

@Configuration
public class RedisConfig {
    /**
     * @Author HJJ
     * @Date 2022-12-30 15:49
     * @Params
     * @Return
     * @Description 注入CacheManager
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
                .cacheDefaults(defaultCacheConfig())
                .transactionAware()
                .build();
    }

    /**
     * @Author HJJ
     * @Date 2022-12-30 15:48
     * @Params
     * @Return
     * @Description 配置通过@Cacheable注解缓存的序列化方式以及过期时间
     */
    private RedisCacheConfiguration defaultCacheConfig() {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        serializer.setObjectMapper(mapper);
        return RedisCacheConfiguration.defaultCacheConfig()
                // 20秒过期
                .entryTtl(Duration.ofSeconds(20))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
                .disableCachingNullValues();
    }
}

2.3 使用Redis缓存数据

在Controller层中,使用@Cacheable注解来缓存return的数据。

@Cacheable(value, key)中,value是属性名称,key是标识,在RedisCli中应该通过get value::key的形式读取数据,如get User::Jackget User::John

package com.example.demo.controller;

/**
 * @Author : HuangJiajian
 * @create 2022/12/2 10:59
 */
@RestController
@RequestMapping("/cache")
public class TestRedis {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/str")
    @Cacheable(key = "#str", value = "Str")
    public String cacheStr(String str) {
        System.out.println("缓存str(第二次同参数时,不应该出现这一打印信息):" + str);
        return cache;
    }
    
    @GetMapping("/user")
    @Cacheable(key = "#username", value = "User")
    public AjaxResult cacheUser(String username) {
        UserEntity userEntity = new UserEntity(u, "123456");
        System.out.println("缓存username(第二次同参数时,不应该出现这一打印信息):" + username);
        return new AjaxResult(AjaxResult.CODE.SUCCESS, "success", userEntity);
    }
}

验证缓存

发送发送2次GET请求/cache/str,参数都是?str=value1,结果如下:

第一次请求:

控制台打印出”缓存str(第二次同参数时,不应该出现这一打印信息):value1“

浏览器获取到数据“value1”

RedisCli运行get Str::value1打印出"value1"

第二次请求:

控制台不打印

浏览器获取到数据“value1”

RedisCli运行get Str::value1打印出"value1"

三、拓展知识

3.1 Redis事务

事务处理简单来讲就是“要么是0,要么是1”。常见于电商系统,如商品在用户提交的订单后库存便减少,但若用户取消支付或支付失败,就需要将库存数据回滚。Redis也具有部分事务处理的功能。

Redis的事务处理包含三个部分:watch(监控)…multi(开始)…exec(执行)

@GetMapping("/multi")
public String testMulti(){
    stringRedisTemplate.opsForValue().set("key1", "value1");
    List list = (List) stringRedisTemplate.execute(new SessionCallback<Object>() {
        @Override
        public Object execute(RedisOperations ops) throws DataAccessException {
            ops.watch("key1");
            ops.multi();
            ops.opsForValue().set("key2", "value2");
            // 还未执行事务,所以数据是空的
            System.out.println(ops.opsForValue().get("key2")); // null
            // 情况1:在multi和exec之间打断点,然后使用reids-cli修改key1的值,exec之后Redis会监听到key1已经发生改变,故会回滚事务。
            // 情况2:key1增操作错误,但Redis仅存在队列中,直到exec时才会报错,应避免
            // ops.opsForValue().increment("key1", 1);
            ops.exec();
            return null;
        }
    });
    System.out.println(list);
    return "end";
}

四、问题记录

4.1 @Cacheable注解失效

@Cacheable的原理是SpringAOP,很多@Cacheable失效的原因都是因为RedisConfig的初始化在其使用位置之后,所以无法执行AOP拦截,导致@Cacheable注解失效。这个可以通过使用@Autowired StringRedisTemplate stringRedisTemplate;实现Redis缓存,但这样并不会用上RedisConfig中的配置,所以需要在函数中自己配置序列化方式和过期时间等。

还有一种是@Cacheable方法A(),然后使用方法B()去调用方法A,我知道你想要让B调用A时,返回A在Redis中的缓存数据,但这样也是无法做到的。

参考文献

  1. 10分钟拿下 HashMap
  2. 深入浅出Spring Boot 2.x
  3. RedisTemplate配置的jackson.ObjectMapper里的一个enableDefaultTyping方法过期解决
### 整合 RedisSpring Boot 3 的教程 在现代应用程序开发中,Redis 是一种广泛使用的内存数据存储解决方案。通过将其集成到 Spring Boot 应用程序中,可以显著提高性能并支持缓存功能。以下是关于如何在 Spring Boot 3 中整合 Redis 的详细说明。 #### 配置依赖项 为了使 Spring BootRedis 能够协同工作,需要引入必要的 Maven 或 Gradle 依赖项。这些依赖项提供了与 Redis 进行交互所需的功能库[^1]。 对于 Maven 构建工具,可以在 `pom.xml` 文件中添加以下内容: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 如果计划使用 Lettuce 客户端 --> <dependency> <groupId>io.lettuce.core</groupId> <artifactId>lettuce-core</artifactId> </dependency> ``` 如果项目基于 Gradle,则应在 `build.gradle` 文件中加入如下配置: ```gradle implementation 'org.springframework.boot:spring-boot-starter-data-redis' // 可选:Lettuce 客户端 implementation 'io.lettuce.core:lettuce-core' ``` 上述依赖会自动导入所需的类和方法来操作 Redis 数据库[^2]。 --- #### 配置文件设置 完成依赖项的添加之后,在项目的 `application.properties` 或者 `application.yml` 文件中定义 Redis 的连接参数。例如: ##### 使用 application.properties: ```properties spring.redis.host=localhost spring.redis.port=6379 spring.redis.password= spring.redis.database=0 ``` ##### 使用 application.yml: ```yaml spring: redis: host: localhost port: 6379 password: "" database: 0 ``` 以上属性指定了 Redis 实例的位置以及访问权限等信息[^3]。 --- #### 创建 Redis 配置类 可以通过创建自定义配置类进一步调整默认行为或者启用特定特性。下面是一个简单的例子展示如何声明一个 Bean 来管理 RedisTemplate 对象实例化过程中的序列化策略。 ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.StringRedisTemplate; @Configuration public class RedisConfig { @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory){ return new StringRedisTemplate(connectionFactory); } } ``` 此代码片段展示了如何利用 Spring 提供的支持机制轻松实现对字符串键值对的操作能力提升效率的同时也增强了灵活性。 --- #### 编写服务逻辑 最后一步就是编写实际业务逻辑去调用 Redis 功能了。这里给出一段示范性的 Java 方法用于保存及检索用户登录状态记录至 Redis 缓存之中: ```java @Service public class LoginService { private final StringRedisTemplate template; public LoginService(StringRedisTemplate template) { this.template = template; } public void saveLoginStatus(String userId, boolean status) { template.opsForValue().set(userId, Boolean.toString(status)); } public Optional<Boolean> getLoginStatus(String userId) { String value = template.opsForValue().get(userId); if (value != null && !value.isEmpty()) { return Optional.of(Boolean.parseBoolean(value)); } else { return Optional.empty(); } } } ``` 这段示例演示了一个典型场景——即当某个用户的在线离线情况发生变化时更新其对应的标记位;而查询部分则负责读取当前已知的状态以便后续处理流程继续执行下去。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值