在当今的软件开发领域,缓存技术是提升应用性能的关键手段之一。Redis 作为一款高性能的键值对存储数据库,凭借其出色的读写速度和丰富的数据结构,在缓存场景中得到了广泛应用。Spring Boot 作为一款简化 Spring 应用开发的框架,与 Redis 的集成可以让开发者轻松地在项目中使用 Redis 缓存。本文将详细介绍如何在 Spring Boot 项目中集成和使用 Redis。
项目搭建
首先在你的项目中引入redis的Maven依赖确保使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在 application.properties
或 application.yml
中配置 Redis 连接信息。以下是 application.yml
的示例配置:
spring:
redis:
database: 0 # Redis服务器数据库
host: 127.0.0.1 # Redis服务器地址
port: 6379 # Redis服务器连接端口
password: 123456 # Redis服务器连接密码(默认为空)
timeout: 6000 # Redis连接超时时间(毫秒)
Redis 基本操作
配置Redis的配置类
package com.lppaa.redisdemo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory){
RedisSerializer<String> keyRedisSerializer = new StringRedisSerializer(); // redis的key序列化方式
Jackson2JsonRedisSerializer valueRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // redis的value的序列化
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
valueRedisSerializer.setObjectMapper(om);
//配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ZERO) // 默认生存时间
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keyRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueRedisSerializer))
.disableCachingNullValues();
//缓存配置map
Map<String,RedisCacheConfiguration> cacheConfigurationMap=new HashMap<>();
//自定义缓存名,后面使用的@Cacheable的CacheName
cacheConfigurationMap.put("myRedis",config);
// cacheConfigurationMap.put("default",config);
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.withInitialCacheConfigurations(cacheConfigurationMap)
.build();
return cacheManager;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
CacheManager方法
:负责管理缓存的创建、获取和清理等操作。此方法对 Redis 缓存管理器进行了配置,具体步骤如下:- 序列化配置:
- 对 Redis 的键使用
StringRedisSerializer
进行序列化。 - 对 Redis 的值使用
Jackson2JsonRedisSerializer
进行序列化,同时配置ObjectMapper
以避免查询缓存时出现转换异常。
- 对 Redis 的键使用
- 缓存配置:
- 借助
RedisCacheConfiguration
配置默认的缓存策略,包含默认生存时间、键和值的序列化方式,并且禁止缓存空值。 - 创建一个
Map
来存放自定义的缓存配置,这里定义了一个名为"myRedis"
的缓存。
- 借助
- 缓存管理器构建:
- 利用
RedisCacheManager.builder
构建缓存管理器,设置默认缓存配置以及自定义的缓存配置。
- 利用
- 序列化配置:
-
redisTemplate方法
:作用是在代码里对 Redis 进行操作- 采用
StringRedisTemplate
作为基础模板,它是RedisTemplate
的子类,专门用于处理字符串类型的键和值。 - 同样使用
Jackson2JsonRedisSerializer
对值进行序列化,并且配置ObjectMapper
以防止查询缓存时出现转换异常。
- 采用
编写服务层逻辑
EmployeeService接口类
public interface EmployeeService {
List<Employee> findAll();
Employee findById(Integer id);
Employee update(Employee employee);
Integer delete(Integer id);
}
EmployeeServiceImpl接口实现类
package com.lppaa.redisdemo.service.serviceImpl;
import com.lppaa.redisdemo.dao.EmployeeDao;
import com.lppaa.redisdemo.entity.Employee;
import com.lppaa.redisdemo.service.EmployeeService;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public List<Employee> findAll() {
return employeeDao.findAll();
}
@Override
@Cacheable(cacheNames = "myRedis" ,key = "T(com.lppaa.redisdemo.utils.MD5Utils).md5('EmployeeService_findById' + #id)" ,unless = "#result==null")
public Employee findById(Integer id) {
System.out.println("进入方法,去数据库查询");
return employeeDao.findById(id);
}
@Override
@CachePut(cacheNames = "myRedis", key = "T(com.lppaa.redisdemo.utils.MD5Utils).md5('EmployeeService_findById' + #employee.id)",condition = "#result != null")
public Employee update(Employee employee) {
employee.setTime(new Date());
Integer ans = employeeDao.update(employee);
if(ans>0)
return employeeDao.findById(employee.getId());
return null;//表示更新失败 结果为空 不存入缓存 结果不变
}
@Override
@CacheEvict(cacheNames = "myRedis", key = "T(com.lppaa.redisdemo.utils.MD5Utils).md5('EmployeeService_findById' + #id)")
public Integer delete(Integer id) {
Integer s = employeeDao.delete(id);
return s;
}
}
@Cacheable
注解
@Cacheable
注解:用于标记该方法的结果可以被缓存。cacheNames = "myRedis"
:指定使用名为myRedis
的缓存,这个缓存名称在RedisConfig
类中配置。key = "T(com.lppaa.redisdemo.utils.MD5Utils).md5('EmployeeService_findById' + #id)"
:使用 SpEL(Spring Expression Language)表达式生成缓存的键。这里调用MD5Utils
类的md5
方法对"EmployeeService_findById"
和传入的id
拼接后的字符串进行 MD5 加密,确保每个不同的id
对应一个唯一的缓存键。unless = "#result==null"
:表示如果方法的返回结果为null
,则不将结果存入缓存。
- 当调用该方法时,Spring 会先检查缓存中是否存在对应的键,如果存在则直接返回缓存中的结果,否则执行方法体中的代码,从数据库中查询数据,并将结果存入缓存。
@CachePut
注解
@CachePut
注解:用于更新缓存。无论缓存中是否存在对应的键,都会执行方法体中的代码,并将方法的返回结果存入缓存。cacheNames = "myRedis"
:指定使用名为myRedis
的缓存。key = "T(com.lppaa.redisdemo.utils.MD5Utils).md5('EmployeeService_findById' + #employee.id)"
:生成缓存的键,与findById
方法使用相同的键生成策略。condition = "#result != null"
:表示只有当方法的返回结果不为null
时,才将结果存入缓存。
- 该方法首先更新员工的时间戳,然后调用
EmployeeDao
的update
方法更新数据库中的员工信息。如果更新成功,则再次查询数据库获取最新的员工信息并返回,同时更新缓存;如果更新失败,则返回null
,不更新缓存。
CacheEvict
注解
@CacheEvict
注解:用于从缓存中移除指定键的缓存项。cacheNames = "myRedis"
:指定使用名为myRedis
的缓存。key = "T(com.lppaa.redisdemo.utils.MD5Utils).md5('EmployeeService_findById' + #id)"
:生成要移除的缓存键,与findById
和update
方法使用相同的键生成策略。
- 该方法调用
EmployeeDao
的delete
方法从数据库中删除指定id
的员工信息,并从缓存中移除对应的缓存项。
编写控制层逻辑
package com.lppaa.redisdemo.controller;
import com.alibaba.fastjson.JSON;
import com.lppaa.redisdemo.entity.Employee;
import com.lppaa.redisdemo.entity.User;
import com.lppaa.redisdemo.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/test")
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private EmployeeService employeeService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/aaa")
public String testA(){
User user = new User();
user.setName("李四");
user.setAge(20);
// redisTemplate.opsForValue().set("user", JSON.toJSONString(user));
//redisTemplate.opsForValue().set("ttt", user);
stringRedisTemplate.opsForValue().set("qweirj", JSON.toJSONString(user));
return "success";
}
@RequestMapping("/findbyid")
@ResponseBody
public Employee findbyId(Integer id){
Employee employee = employeeService.findById(id);
return employee;
}
@RequestMapping("/update")
@ResponseBody
public String update(Employee e){
e.setTime(new Date());
Employee byId = employeeService.update(e);
if(byId != null)
return "success";
return "false";
}
@RequestMapping("/delete")
@ResponseBody
public String dete(Integer id){
Integer s = employeeService.delete(id);
if(s == 1)
return "success";
return "false";
}
}
最后打开Redis即可进行使用。