【转载】Springboot2.x 使用 Redis

发布时间 2023-12-19 13:15:00作者: 夏秋初

参考

注意

  1. class java.lang.Integer cannot be cast to class com.xiaqiuchu.demo.entity.Student (java.lang.Integer is in module java.base of loader 'bootstrap'; com.xiaqiuchu.demo.entity.Student is in unnamed module of loader 'app')
    注解缓存时缓存的方法缓存值,update 返回的是数字类型,导致缓存查询的时候报错转换失败。

  2. entity 类需要 implements java.io.Serializable ,否则可能会导致缓存储存时序列化失败或错误。

环境

环境 版本 操作
windows 10
vs code 1.84.2
Spring Boot Extension Pack v0.2.1 vscode插件
Extension Pack for Java v0.25.15 vscode插件
JDK 11
Springboot 2.3.12.RELEASE
mybatis-spring-boot-starter 2.1.4 mvn依赖
spring-boot-starter-cache mvn依赖
Apache Maven 3.8.6
Redis 3.0.504 windows 版本,已停更,建议 linux 中使用

步骤

配置

  1. 添加 pom.xml 依赖。
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 在配置文件中 application.properties 增加配置。

不仅仅这些配置,还有其他配置以及连接池的配置

# redis配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
# 连接池配置,连接池配置还需要添加其他依赖。 https://juejin.cn/post/7076244567569203208
  1. src\main\java\com\xiaqiuchu\demo\config 增加 RedisConfig.java
package com.xiaqiuchu.demo.config;

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.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

  @Bean
  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);
    // key 序列化类
    template.setKeySerializer(new StringRedisSerializer());
    // value 序列化类
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return template;
  }
}

使用

  1. 代码操作。
package com.xiaqiuchu.demo.service;

import java.time.Duration;

import javax.annotation.Resource;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import com.xiaqiuchu.demo.entity.Student;
import com.xiaqiuchu.demo.mapper.StudentMapper;

@Service
public class StudentService {
    @Resource
    StudentMapper studentMaper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 手动管理缓存
     * @param id
     * @return
     */
    public Student findByIdFromCache(Integer id){
        String cacheKey = "StudentService" + id;
        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
        if(redisTemplate.hasKey(cacheKey) == null || redisTemplate.getExpire(cacheKey) < 1){
            System.out.println("==查询数据库==");
            valueOperations.set(cacheKey, studentMaper.findById(id), Duration.ofHours(2));
        }
        return (Student) valueOperations.get(cacheKey);
    }
}

  1. 注解方式

注意:注解方式是缓存的方法返回值,但是像 mybatis 中 update 操作默认返回的是更新条数,如果直接返回更新条数就会导致缓存储存为数字类型,在查询的时候报错 class java.lang.Integer cannot be cast to class com.xiaqiuchu.demo.entity.Student (java.lang.Integer is in module java.base of loader 'bootstrap'; com.xiaqiuchu.demo.entity.Student is in unnamed module of loader 'app')

注解方式获取 key 可以通过 . 方式获取对象的属性。

package com.xiaqiuchu.demo.service;

import javax.annotation.Resource;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.xiaqiuchu.demo.entity.Student;
import com.xiaqiuchu.demo.mapper.StudentMapper;

@Service
public class StudentService {
    @Resource
    StudentMapper studentMaper;

    // 该注解用于标记方法的返回结果可以被缓存。当下次调用相同的方法时,如果缓存中存在相同的参数,则直接从缓存中获取结果,而不执行方法体内的代码。如果缓存中不存在相同的参数,则执行方法体内的代码,并将结果存入缓存中。
    @Cacheable(value = "StudentService", key = "#id")
    public Student findById(Integer id){
        System.out.println("==查询==");
        return studentMaper.findById(id);
    }

    public Integer insert(Student student){
        return studentMaper.insert(student);
    }

    // 该注解用于标记方法的返回结果需要放入缓存。无论缓存中是否已存在相同的参数,每次调用该方法都会执行方法体内的代码,并将结果存入缓存中。
    // 方法返回类型要一致,不然储存的就是 Integer。。。 
    @CachePut(value = "StudentService", key = "#student.id")
    public Student updateById(Student student){
        Integer updateNum = studentMaper.updateById(student);
        Assert.isTrue(updateNum > 0, "更新失败");
        return student;
    }

    // 该注解用于标记方法执行后需要清除特定的缓存项。可以指定要清除的缓存项的key,或者通过allEntries参数设置为true来清除所有缓存项。
    @CacheEvict(value = "StudentService", key = "#id")
    public Integer deleteById(Integer id){
        System.out.println("==删除==");
        return studentMaper.deleteById(id);
    }
    
}