一、前言
在当今的互联网应用开发中,业务性能优化是至关重要的一环。随着用户数量的增加和业务复杂度的提升,数据库的压力也越来越大,响应时间变长,用户体验随之下降。而缓存技术的出现,为解决这些问题提供了有效的途径。其中,Redis凭借其高性能、多数据结构的特性,成为缓存、分布式锁、限流等场景的首选中间件。Spring Boot作为主流的Java开发框架,通过自动配置机制简化了Redis的集成流程,让开发者无需关注复杂的底层实现,即可快速上手。
二、环境准备
2.1 安装Redis服务
Redis支持Windows、Linux、Mac多平台部署,推荐使用Docker快速搭建(避免环境配置冲突):
# 拉取Redis镜像
docker pull redis:6.2.6
# 启动容器
docker run -d -p 6379:6379 --name redis-demo redis --requirepass "123456"
# 验证连接
redis-cli -h localhost -p 6379 -a 123456
输入ping返回PONG即表示连接成功。
2.2 前置条件
确保Redis服务端已部署(本地或云服务器,推荐Redis 6.x+),并满足以下条件:
- Redis服务正常运行,IP、端口(默认6379)、密码正确
- 服务器防火墙开放6379端口(云服务器需配置安全组)
- 客户端与Redis版本兼容(Jedis 3.8.0兼容Redis 6.x+,Redisson 3.25.2兼容Redis 6.x+)
三、项目依赖配置
3.1 基础依赖配置
创建Spring Boot项目(推荐2.7.x版本,兼容性更优),在pom.xml中添加Redis核心依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
spring-boot-starter-data-redis包含Redis自动配置类和核心API,commons-pool2提供连接池支持,优化Redis连接性能。
3.2 客户端选型
Spring Boot 2.x+默认内置Lettuce客户端,无需额外排除依赖。完整POM依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
若业务需使用Jedis客户端,需先排除默认Lettuce依赖,再引入Jedis和连接池依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
对于分布式场景,推荐集成Redisson,可与Lettuce/Jedis共存,直接引入Starter实现自动配置:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.25.2</version>
</dependency>
四、Redis连接配置
4.1 基础连接配置
在application.yml中配置Redis连接信息,覆盖默认自动配置:
spring:
redis:
# 连接信息
host: localhost
port: 6379
password: 123456
database: 0 # 选择第0个数据库(Redis默认16个数据库)
# 连接池配置(Lettuce)
lettuce:
pool:
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 2 # 最小空闲连接
max-wait: 1000ms # 连接等待超时时间
timeout: 5000ms # 命令执行超时时间
数据库索引database用于隔离不同业务数据,避免键名冲突。连接池参数需根据业务压力调整,避免连接泄露或资源浪费。
4.2 集群模式配置
适用于Redis集群部署场景(至少3主3从),配置需包含所有主从节点:
spring:
redis:
cluster:
nodes:
- 192.168.1.101:6379
- 192.168.1.102:6379
- 192.168.1.103:6379
max-redirects: 3 # 最大重定向次数
password: 123456
timeout: 3000ms
4.3 Redisson配置
Redisson需单独配置连接信息,支持单机/集群模式,且默认已集成Jackson序列化(无需额外处理Key乱码):
spring:
redis:
redisson:
file: classpath:/redisson-config.yml
在src/main/resources下创建redisson-config.yml:
singleServerConfig:
address: "redis://localhost:6379"
password: "123456"
database: 0
connectionPoolSize: 64
idleConnectionTimeout: 10000
connectTimeout: 3000
timeout: 3000
codec: !<org.redisson.codec.JsonJacksonCodec> {}
五、序列化配置优化
5.1 默认序列化问题
Spring Boot默认使用JdkSerializationRedisSerializer序列化对象,存在可读性差、占用空间大的问题。推荐自定义序列化配置,使用Jackson2JsonRedisSerializer实现JSON序列化。
5.2 自定义RedisTemplate配置
创建配置类,配置RedisTemplate序列化方式和各种Operations:
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 设置Key序列化器
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// 设置Value序列化器(JSON序列化,推荐)
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
}
六、数据操作实战
6.1 字符串操作
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 存入键值对(无过期时间)
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
// 存入键值对(设置过期时间)
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
// 获取值
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
// 自增操作(计数器场景)
public Long increment(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
// 批量操作
public void multiSet(Map<String, Object> map) {
redisTemplate.opsForValue().multiSet(map);
}
}
6.2 哈希操作
@Service
public class RedisHashService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 存入哈希数据
public void put(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
// 获取单个属性
public Object get(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
// 获取所有属性
public Map<Object, Object> entries(String key) {
return redisTemplate.opsForHash().entries(key);
}
// 删除指定字段
public Long delete(String key, Object... hashKeys) {
return redisTemplate.opsForHash().delete(key, hashKeys);
}
}
6.3 列表操作
@Service
public class RedisListService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 左侧插入
public Long leftPush(String key, Object value) {
return redisTemplate.opsForList().leftPush(key, value);
}
// 右侧插入
public Long rightPush(String key, Object value) {
return redisTemplate.opsForList().rightPush(key, value);
}
// 获取列表范围
public List<Object> range(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
// 获取列表长度
public Long size(String key) {
return redisTemplate.opsForList().size(key);
}
}
6.4 集合操作
@Service
public class RedisSetService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 添加元素
public Long add(String key, Object... values) {
return redisTemplate.opsForSet().add(key, values);
}
// 获取所有元素
public Set<Object> members(String key) {
return redisTemplate.opsForSet().members(key);
}
// 判断元素是否存在
public Boolean isMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
// 获取集合大小
public Long size(String key) {
return redisTemplate.opsForSet().size(key);
}
}
6.5 有序集合操作
@Service
public class RedisZSetService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 添加元素(带分数)
public Boolean add(String key, Object value, double score) {
return redisTemplate.opsForZSet().add(key, value, score);
}
// 获取分数范围内的元素
public Set<Object> rangeByScore(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}
// 获取排名
public Long rank(String key, Object value) {
return redisTemplate.opsForZSet().rank(key, value);
}
// 获取分数
public Double score(String key, Object value) {
return redisTemplate.opsForZSet().score(key, value);
}
}
七、缓存注解使用
7.1 启用缓存支持
在启动类或配置类上添加@EnableCaching注解:
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
7.2 常用缓存注解
@Cacheable – 缓存查询
@Service
@CacheConfig(cacheNames = "user")
public class UserService {
@Cacheable(key = "#id", unless = "#result == null")
public User findById(Long id) {
// 如果缓存中没有,则执行方法并将结果存入缓存
return userRepository.findById(id).orElse(null);
}
}
参数说明:
value/cacheNames:缓存名称key:缓存键,支持SpEL表达式condition:条件缓存,满足条件才缓存unless:条件不缓存,满足条件不缓存
@CachePut – 更新缓存
@CachePut(key = "#user.id")
public User save(User user) {
// 每次都会执行方法,并将结果更新到缓存
return userRepository.save(user);
}
与@Cacheable不同的是,@CachePut每次都会触发真实查询方法的调用。
@CacheEvict – 删除缓存
@CacheEvict(key = "#id")
public void deleteById(Long id) {
// 删除数据库记录后,同时删除缓存
userRepository.deleteById(id);
}
参数说明:
allEntries:是否清空所有缓存内容,默认为falsebeforeInvocation:是否在方法执行前清空,默认为false
@Caching – 组合多个缓存操作
@Caching(
put = @CachePut(key = "#user.id"),
evict = @CacheEvict(key = "'list'", allEntries = true)
)
public User update(User user) {
return userRepository.save(user);
}
7.3 自定义Key生成器
可以自定义缓存键生成策略:
@Configuration
public class RedisConfig {
@Bean
public KeyGenerator customKeyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}
使用自定义Key生成器:
@Cacheable(value = "users", keyGenerator = "customKeyGenerator")
public User getUserByEmail(String email) {
return userRepository.findByEmail(email);
}
八、常见问题与解决方案
8.1 连接配置问题
问题现象:Unable to connect to Redis server: 127.0.0.1:6379
解决方案:
- 确保Redis服务已启动:
redis-cli ping返回PONG - 检查防火墙是否开放6379端口
- 验证配置文件的host、port、password是否正确
- 关闭Redis保护模式(仅测试环境):
config set protected-mode no
8.2 序列化异常
问题现象:SerializationException: Cannot serialize
解决方案:
- 实体类实现
Serializable接口 - 使用JSON序列化器替代默认JDK序列化
- 配置自定义RedisTemplate,指定Jackson序列化器
8.3 连接池异常
问题现象:Could not get a resource from the pool
解决方案:
- 优化连接池参数配置
- 检查连接泄漏问题
- 增加连接池最大连接数
- 检查Redis服务端
maxclients限制
8.4 缓存穿透、雪崩、击穿
缓存穿透:查询不存在的数据,导致请求直接打到数据库
- 解决方案:缓存空值、布隆过滤器
缓存雪崩:大量Key同时过期
- 解决方案:设置随机过期时间、热点数据永不过期
缓存击穿:热点Key过期瞬间,大量请求涌入数据库
- 解决方案:加互斥锁、永不过期
九、性能优化建议
- 连接池优化:根据业务压力调整连接池参数,避免连接泄露或资源浪费
- 序列化优化:使用JSON序列化替代JDK序列化,提升性能和可读性
- 缓存策略:采用本地缓存+Redis二级缓存架构,热点数据采用本地缓存
- 数据一致性:重要数据配置AOF持久化策略,确保数据安全
- 监控告警:通过Spring Boot Actuator监控Redis连接池状态,设置告警阈值
十、总结
Spring Boot集成Redis是一个简单而强大的技术组合,通过自动配置和丰富的API,开发者可以快速实现高性能的缓存系统。本文从环境准备、依赖配置、连接管理、序列化优化、数据操作、缓存注解、常见问题等多个维度,详细介绍了Spring Boot集成Redis的完整流程。在实际项目中,建议根据业务场景选择合适的缓存策略,并注意数据一致性和性能优化,才能构建出稳定可靠的分布式缓存系统。