RedisTemplate 实战:Spring 项目中 Redis 操作的全维度指南
在 Spring 生态中,RedisTemplate 是操作 Redis 的核心工具类,它封装了 Redis 的底层命令,让开发者能以面向对象的方式轻松操作 Redis 各种数据结构。本文将从配置、基础使用到高级场景,全面讲解如何在 Spring 项目中利用 RedisTemplate 玩转 Redis。
一、RedisTemplate 配置与初始化
要在 Spring 项目中使用 RedisTemplate,首先需要完成依赖引入和配置类编写。
1. 引入依赖(Maven)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 可选:使用 Lettuce 连接池(Spring Boot 默认推荐) -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
2. 编写 Redis 配置类
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 {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// Key 序列化器:使用 String 序列化template.setKeySerializer(new StringRedisSerializer());// Value 序列化器:使用 JSON 序列化,支持对象存储template.setValueSerializer(new GenericJackson2JsonRedisSerializer());// Hash Key 序列化器template.setHashKeySerializer(new StringRedisSerializer());// Hash Value 序列化器template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());template.afterPropertiesSet();return template;}
}
配置说明:
- 序列化器选择:
StringRedisSerializer保证 Key 是可读的字符串;GenericJackson2JsonRedisSerializer支持对象的 JSON 序列化 / 反序列化,可直接存储实体类。 - 连接工厂:由 Spring Boot 自动配置,默认使用 Lettuce 连接池(高性能、线程安全)。
二、RedisTemplate 核心操作:五大数据结构实战
1. 字符串(String)操作
字符串是 Redis 最基础的数据结构,RedisTemplate 中通过 opsForValue() 进行操作。
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;@Component
public class RedisStringService {@Resourceprivate RedisTemplate<String, Object> redisTemplate;// 设置字符串public void setString(String key, String value) {redisTemplate.opsForValue().set(key, value);}// 设置带过期时间的字符串(单位:秒)public void setStringWithExpire(String key, String value, long seconds) {redisTemplate.opsForValue().set(key, value, seconds);}// 获取字符串public String getString(String key) {return (String) redisTemplate.opsForValue().get(key);}// 数字自增public Long increment(String key, long delta) {return redisTemplate.opsForValue().increment(key, delta);}// 数字自减public Long decrement(String key, long delta) {return redisTemplate.opsForValue().decrement(key, delta);}
}
场景示例:用户登录次数统计、文章阅读量计数。
2. 哈希(Hash)操作
哈希适合存储对象(如用户信息、商品详情),通过 opsForHash() 操作。
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Map;@Component
public class RedisHashService {@Resourceprivate RedisTemplate<String, Object> redisTemplate;// 设置哈希字段public void putHash(String key, String hashKey, Object value) {redisTemplate.opsForHash().put(key, hashKey, value);}// 批量设置哈希字段public void putAllHash(String key, Map<String, Object> map) {redisTemplate.opsForHash().putAll(key, map);}// 获取哈希字段public Object getHash(String key, String hashKey) {return redisTemplate.opsForHash().get(key, hashKey);}// 获取所有哈希字段和值public Map<Object, Object> getAllHash(String key) {return redisTemplate.opsForHash().entries(key);}// 删除哈希字段public Long deleteHash(String key, Object... hashKeys) {return redisTemplate.opsForHash().delete(key, hashKeys);}
}
场景示例:存储用户信息(user:1001 作为 Key,name/age/gender 作为 HashKey)。
3. 列表(List)操作
列表是有序可重复的集合,支持两端插入 / 弹出,通过 opsForList() 操作。
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.List;@Component
public class RedisListService {@Resourceprivate 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 Object leftPop(String key) {return redisTemplate.opsForList().leftPop(key);}// 从列表右侧弹出元素public Object rightPop(String key) {return redisTemplate.opsForList().rightPop(key);}// 获取列表指定范围元素public List<Object> range(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}
}
场景示例:消息队列(leftPush 生产,rightPop 消费)、用户操作时间轴。
4. 集合(Set)操作
集合是无序不可重复的集合,支持交集、并集运算,通过 opsForSet() 操作。
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Set;@Component
public class RedisSetService {@Resourceprivate 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 Set<Object> intersect(String key1, String key2) {return redisTemplate.opsForSet().intersect(key1, key2);}
}
场景示例:用户标签(user:1001:tags 存储用户兴趣标签)、好友共同关注。
5. 有序集合(ZSet)操作
有序集合按分数排序,适合排行榜场景,通过 opsForZSet() 操作。
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Set;@Component
public class RedisZSetService {@Resourceprivate RedisTemplate<String, Object> redisTemplate;// 向有序集合添加元素(带分数)public Boolean add(String key, Object value, double score) {return redisTemplate.opsForZSet().add(key, value, score);}// 按分数升序获取元素public Set<Object> range(String key, long start, long end) {return redisTemplate.opsForZSet().range(key, start, end);}// 按分数降序获取元素(带分数)public Set<org.springframework.data.redis.core.ZSetOperations.TypedTuple<Object>> rangeWithScores(String key, long start, long end) {return redisTemplate.opsForZSet().rangeWithScores(key, start, end);}// 元素分数自增public Double incrementScore(String key, Object value, double delta) {return redisTemplate.opsForZSet().incrementScore(key, value, delta);}// 获取元素排名(升序)public Long rank(String key, Object value) {return redisTemplate.opsForZSet().rank(key, value);}
}
场景示例:文章阅读量排行榜(rank:article 作为 Key,文章 ID 作为 Value,阅读量作为 Score)。
三、RedisTemplate 高级特性
1. 事务支持
RedisTemplate 支持 Redis 事务,通过 multi()/exec() 实现。
public void transactionDemo() {redisTemplate.multi(); // 开启事务redisTemplate.opsForValue().set("key1", "value1");redisTemplate.opsForValue().set("key2", "value2");List<Object> results = redisTemplate.exec(); // 执行事务// results 包含每个命令的执行结果
}
注意:Redis 事务是 “弱事务”,仅保证命令的原子性(要么全执行,要么全不执行),但不支持回滚。
2. 管道(Pipeline)
管道用于批量执行命令,减少网络往返次数,提升性能。
public void pipelineDemo() {redisTemplate.executePipelined((RedisCallback<Object>) connection -> {for (int i = 0; i < 1000; i++) {connection.set(redisTemplate.getKeySerializer().serialize("key:" + i),redisTemplate.getValueSerializer().serialize("value:" + i));}return null;});
}
3. 分布式锁
基于 RedisTemplate 实现简单分布式锁:
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;@Component
public class RedisDistributedLock {@Resourceprivate RedisTemplate<String, Object> redisTemplate;private static final String LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();UNLOCK_SCRIPT.setScriptText(LOCK_SCRIPT);UNLOCK_SCRIPT.setResultType(Long.class);}// 加锁public boolean lock(String key, long expireTime, TimeUnit timeUnit) {String uuid = UUID.randomUUID().toString();Boolean result = redisTemplate.opsForValue().setIfAbsent(key, uuid, expireTime, timeUnit);return result != null && result;}// 解锁public boolean unlock(String key) {String uuid = (String) redisTemplate.opsForValue().get(key);if (uuid == null) {return false;}Long result = redisTemplate.execute(UNLOCK_SCRIPT, Collections.singletonList(key), uuid);return result != null && result > 0;}
}
四、最佳实践与避坑指南
1. 序列化器选择
- Key 序列化:统一使用
StringRedisSerializer,保证 Key 是可读的字符串。 - Value 序列化:
- 存储简单类型(String、Integer):可用
StringRedisSerializer; - 存储实体类:推荐
GenericJackson2JsonRedisSerializer或Jackson2JsonRedisSerializer,支持对象的序列化 / 反序列化。
- 存储简单类型(String、Integer):可用
2. 连接池配置(Lettuce)
在 application.yml 中配置连接池参数,避免连接泄漏或性能瓶颈:
spring:redis:lettuce:pool:max-active: 8 # 最大连接数max-idle: 8 # 最大空闲连接数min-idle: 0 # 最小空闲连接数max-wait: -1ms # 连接获取超时时间(-1 表示不超时)
3. 避免常见问题
- BigKey 问题:避免存储过大的字符串或哈希,否则会阻塞 Redis 线程。可拆分大对象或使用 Redis 分片。
- 热点 Key 问题:热点 Key 可通过本地缓存 + Redis 多级缓存缓解压力。
- 事务与 Pipeline 混用:事务和管道不要同时使用,否则可能导致命令执行顺序异常。
总结
RedisTemplate 是 Spring 整合 Redis 的 “利器”,它封装了 Redis 所有核心数据结构的操作,同时提供事务、管道、分布式锁等高级功能。掌握它的使用,能让你在 Spring 项目中高效地利用 Redis 实现缓存、计数、队列、排行榜等场景。
在实际开发中,建议将 RedisTemplate 封装为工具类(如本文开头的 RedisService),统一管理 Redis 操作,提升代码的可维护性和可读性。
