目录
[1. 项目依赖 (pom.xml)](#1. 项目依赖 (pom.xml))
[2. 应用配置文件 (application.yml)](#2. 应用配置文件 (application.yml))
[3. Redis 配置类](#3. Redis 配置类)
[4. Redis 操作工具类](#4. Redis 操作工具类)
[1. Set 类型实际应用场景](#1. Set 类型实际应用场景)
[2. ZSet 类型实际应用场景](#2. ZSet 类型实际应用场景)
[3. Hash 类型实际应用场景](#3. Hash 类型实际应用场景)
下面是一个完整的 Spring Boot 项目示例,展示了如何使用 RedisTemplate 操作 Redis 的各种数据类型。
1. 项目依赖 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>redis-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Redis客户端 Lettuce (默认) -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
<!-- 对象序列化支持 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 应用配置文件 (application.yml)
server:
port: 8080
spring:
redis:
# Redis 服务器地址
host: localhost
# Redis 服务器端口
port: 6379
# Redis 数据库索引(默认为 0)
database: 0
# 连接超时时间
timeout: 5000ms
# 密码(如果没有密码则不配置)
# password: yourpassword
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
logging:
level:
com.example.redis: debug
3. Redis 配置类
package com.example.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
/**
* 配置 RedisTemplate
* 设置 key 和 value 的序列化方式
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用 Jackson2JsonRedisSerializer 序列化 value
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL
);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 使用 StringRedisSerializer 序列化 key
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key 采用 String 序列化
template.setKeySerializer(stringRedisSerializer);
// hash 的 key 也采用 String 序列化
template.setHashKeySerializer(stringRedisSerializer);
// value 采用 Jackson 序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash 的 value 采用 Jackson 序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
4. Redis 操作工具类
package com.example.redis.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// ============================== 通用操作 ==============================
/**
* 设置过期时间
*/
public Boolean expire(String key, long time) {
try {
if (time > 0) {
return redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return false;
} catch (Exception e) {
log.error("设置过期时间失败 key: {}, error: {}", key, e.getMessage());
return false;
}
}
/**
* 获取过期时间
*/
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断 key 是否存在
*/
public Boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
log.error("判断 key 是否存在失败 key: {}, error: {}", key, e.getMessage());
return false;
}
}
/**
* 删除 key
*/
public Boolean delete(String key) {
try {
return redisTemplate.delete(key);
} catch (Exception e) {
log.error("删除 key 失败 key: {}, error: {}", key, e.getMessage());
return false;
}
}
// ============================== String 操作 ==============================
/**
* 设置 String 类型值
*/
public void setString(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
log.info("设置 String 成功 key: {}, value: {}", key, value);
} catch (Exception e) {
log.error("设置 String 失败 key: {}, error: {}", key, e.getMessage());
}
}
/**
* 设置 String 类型值并设置过期时间
*/
public void setString(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
setString(key, value);
}
log.info("设置 String 成功 key: {}, value: {}, time: {}", key, value, time);
} catch (Exception e) {
log.error("设置 String 失败 key: {}, error: {}", key, e.getMessage());
}
}
/**
* 获取 String 类型值
*/
public Object getString(String key) {
try {
Object value = redisTemplate.opsForValue().get(key);
log.info("获取 String 成功 key: {}, value: {}", key, value);
return value;
} catch (Exception e) {
log.error("获取 String 失败 key: {}, error: {}", key, e.getMessage());
return null;
}
}
/**
* 递增
*/
public Long increment(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*/
public Long decrement(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().decrement(key, delta);
}
// ============================== List 操作 ==============================
/**
* 获取 list 缓存的内容
*/
public List<Object> getList(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
log.error("获取 List 失败 key: {}, error: {}", key, e.getMessage());
return null;
}
}
/**
* 获取 list 缓存的长度
*/
public Long getListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error("获取 List 长度失败 key: {}, error: {}", key, e.getMessage());
return 0L;
}
}
/**
* 通过索引获取 list 中的值
*/
public Object getListByIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
log.error("通过索引获取 List 值失败 key: {}, index: {}, error: {}",
key, index, e.getMessage());
return null;
}
}
/**
* 将值放入 list 缓存(从右边添加)
*/
public void rightPushList(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
log.info("List 右插入成功 key: {}, value: {}", key, value);
} catch (Exception e) {
log.error("List 右插入失败 key: {}, error: {}", key, e.getMessage());
}
}
// ============================== Set 数据类型详细操作 ==============================
/**
* 向Set中添加多个元素(带过期时间)
*/
public Long addToSetWithExpire(String key, long expireSeconds, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (expireSeconds > 0) {
redisTemplate.expire(key, expireSeconds, TimeUnit.SECONDS);
}
log.info("Set添加成功 key: {}, values: {}, count: {}, expire: {}秒",
key, Arrays.toString(values), count, expireSeconds);
return count;
} catch (Exception e) {
log.error("Set添加失败 key: {}, error: {}", key, e.getMessage());
return 0L;
}
}
/**
* 获取Set中的所有元素(随机顺序)
*/
public Set<Object> getAllSetMembers(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error("获取Set所有元素失败 key: {}, error: {}", key, e.getMessage());
return Collections.emptySet();
}
}
/**
* 随机获取Set中的一个元素
*/
public Object getRandomSetMember(String key) {
try {
return redisTemplate.opsForSet().randomMember(key);
} catch (Exception e) {
log.error("随机获取Set元素失败 key: {}, error: {}", key, e.getMessage());
return null;
}
}
/**
* 随机获取Set中的多个元素(可能重复)
*/
public List<Object> getRandomSetMembers(String key, long count) {
try {
return redisTemplate.opsForSet().randomMembers(key, count);
} catch (Exception e) {
log.error("随机获取多个Set元素失败 key: {}, count: {}, error: {}",
key, count, e.getMessage());
return Collections.emptyList();
}
}
/**
* 随机移除并返回Set中的一个元素
*/
public Object popRandomSetMember(String key) {
try {
Object member = redisTemplate.opsForSet().pop(key);
log.info("弹出Set随机元素 key: {}, member: {}", key, member);
return member;
} catch (Exception e) {
log.error("弹出Set随机元素失败 key: {}, error: {}", key, e.getMessage());
return null;
}
}
/**
* 随机移除并返回Set中的多个元素
*/
public List<Object> popRandomSetMembers(String key, long count) {
try {
List<Object> members = redisTemplate.opsForSet().pop(key, count);
log.info("弹出多个Set随机元素 key: {}, members: {}", key, members);
return members;
} catch (Exception e) {
log.error("弹出多个Set随机元素失败 key: {}, count: {}, error: {}",
key, count, e.getMessage());
return Collections.emptyList();
}
}
/**
* 获取两个Set的并集
*/
public Set<Object> setUnion(String key1, String key2) {
try {
return redisTemplate.opsForSet().union(key1, key2);
} catch (Exception e) {
log.error("获取Set并集失败 key1: {}, key2: {}, error: {}",
key1, key2, e.getMessage());
return Collections.emptySet();
}
}
/**
* 获取多个Set的并集
*/
public Set<Object> setUnion(Collection<String> keys) {
try {
return redisTemplate.opsForSet().union(keys);
} catch (Exception e) {
log.error("获取多个Set并集失败 keys: {}, error: {}", keys, e.getMessage());
return Collections.emptySet();
}
}
/**
* 获取两个Set的交集
*/
public Set<Object> setIntersect(String key1, String key2) {
try {
return redisTemplate.opsForSet().intersect(key1, key2);
} catch (Exception e) {
log.error("获取Set交集失败 key1: {}, key2: {}, error: {}",
key1, key2, e.getMessage());
return Collections.emptySet();
}
}
/**
* 获取两个Set的差集(key1中有但key2中没有的元素)
*/
public Set<Object> setDifference(String key1, String key2) {
try {
return redisTemplate.opsForSet().difference(key1, key2);
} catch (Exception e) {
log.error("获取Set差集失败 key1: {}, key2: {}, error: {}",
key1, key2, e.getMessage());
return Collections.emptySet();
}
}
/**
* 将一个Set中的元素移动到另一个Set
*/
public Boolean moveSetMember(String sourceKey, Object value, String destinationKey) {
try {
Boolean moved = redisTemplate.opsForSet().move(sourceKey, value, destinationKey);
log.info("移动Set元素 sourceKey: {}, value: {}, destinationKey: {}, result: {}",
sourceKey, value, destinationKey, moved);
return moved;
} catch (Exception e) {
log.error("移动Set元素失败 sourceKey: {}, destinationKey: {}, error: {}",
sourceKey, destinationKey, e.getMessage());
return false;
}
}
// ============================== ZSet 数据类型详细操作 ==============================
/**
* 向ZSet中添加多个元素
*/
public Long addToZSet(String key, Map<Object, Double> valueScoreMap) {
try {
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
for (Map.Entry<Object, Double> entry : valueScoreMap.entrySet()) {
tuples.add(new DefaultTypedTuple<>(entry.getKey(), entry.getValue()));
}
Long count = redisTemplate.opsForZSet().add(key, tuples);
log.info("ZSet批量添加成功 key: {}, 添加数量: {}", key, count);
return count;
} catch (Exception e) {
log.error("ZSet批量添加失败 key: {}, error: {}", key, e.getMessage());
return 0L;
}
}
/**
* 增加ZSet中某个元素的分数
*/
public Double incrementZSetScore(String key, Object value, double delta) {
try {
Double newScore = redisTemplate.opsForZSet().incrementScore(key, value, delta);
log.info("ZSet增加分数成功 key: {}, value: {}, delta: {}, newScore: {}",
key, value, delta, newScore);
return newScore;
} catch (Exception e) {
log.error("ZSet增加分数失败 key: {}, value: {}, error: {}",
key, value, e.getMessage());
return null;
}
}
/**
* 减少ZSet中某个元素的分数
*/
public Double decrementZSetScore(String key, Object value, double delta) {
try {
Double newScore = redisTemplate.opsForZSet().incrementScore(key, value, -delta);
log.info("ZSet减少分数成功 key: {}, value: {}, delta: {}, newScore: {}",
key, value, delta, newScore);
return newScore;
} catch (Exception e) {
log.error("ZSet减少分数失败 key: {}, value: {}, error: {}",
key, value, e.getMessage());
return null;
}
}
/**
* 获取ZSet中指定排名范围的元素和分数
*/
public Set<ZSetOperations.TypedTuple<Object>> getZSetRangeWithScores(String key, long start, long end) {
try {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
} catch (Exception e) {
log.error("获取ZSet元素和分数失败 key: {}, start: {}, end: {}, error: {}",
key, start, end, e.getMessage());
return Collections.emptySet();
}
}
/**
* 获取ZSet中指定分数范围的元素和分数
*/
public Set<ZSetOperations.TypedTuple<Object>> getZSetRangeByScoreWithScores(
String key, double min, double max) {
try {
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
} catch (Exception e) {
log.error("获取ZSet分数范围的元素和分数失败 key: {}, min: {}, max: {}, error: {}",
key, min, max, e.getMessage());
return Collections.emptySet();
}
}
/**
* 获取ZSet中指定分数范围的元素和分数(带分页)
*/
public Set<ZSetOperations.TypedTuple<Object>> getZSetRangeByScoreWithScores(
String key, double min, double max, long offset, long count) {
try {
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, offset, count);
} catch (Exception e) {
log.error("获取ZSet分数范围的元素和分数(分页)失败 key: {}, min: {}, max: {}, offset: {}, count: {}, error: {}",
key, min, max, offset, count, e.getMessage());
return Collections.emptySet();
}
}
/**
* 获取ZSet中指定值的排名(降序)
*/
public Long getZSetReverseRank(String key, Object value) {
try {
return redisTemplate.opsForZSet().reverseRank(key, value);
} catch (Exception e) {
log.error("获取ZSet反向排名失败 key: {}, value: {}, error: {}",
key, value, e.getMessage());
return null;
}
}
/**
* 获取ZSet中指定分数范围的元素数量
*/
public Long getZSetCountByScore(String key, double min, double max) {
try {
return redisTemplate.opsForZSet().count(key, min, max);
} catch (Exception e) {
log.error("获取ZSet分数范围数量失败 key: {}, min: {}, max: {}, error: {}",
key, min, max, e.getMessage());
return 0L;
}
}
/**
* 移除ZSet中指定排名范围的元素
*/
public Long removeZSetRangeByRank(String key, long start, long end) {
try {
Long count = redisTemplate.opsForZSet().removeRange(key, start, end);
log.info("移除ZSet排名范围元素成功 key: {}, start: {}, end: {}, count: {}",
key, start, end, count);
return count;
} catch (Exception e) {
log.error("移除ZSet排名范围元素失败 key: {}, start: {}, end: {}, error: {}",
key, start, end, e.getMessage());
return 0L;
}
}
/**
* 移除ZSet中指定分数范围的元素
*/
public Long removeZSetRangeByScore(String key, double min, double max) {
try {
Long count = redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
log.info("移除ZSet分数范围元素成功 key: {}, min: {}, max: {}, count: {}",
key, min, max, count);
return count;
} catch (Exception e) {
log.error("移除ZSet分数范围元素失败 key: {}, min: {}, max: {}, error: {}",
key, min, max, e.getMessage());
return 0L;
}
}
/**
* 获取ZSet中最小分数
*/
public Double getZSetMinScore(String key) {
try {
Set<ZSetOperations.TypedTuple<Object>> set = redisTemplate.opsForZSet()
.rangeWithScores(key, 0, 0);
if (set != null && !set.isEmpty()) {
return set.iterator().next().getScore();
}
return null;
} catch (Exception e) {
log.error("获取ZSet最小分数失败 key: {}, error: {}", key, e.getMessage());
return null;
}
}
/**
* 获取ZSet中最大分数
*/
public Double getZSetMaxScore(String key) {
try {
Set<ZSetOperations.TypedTuple<Object>> set = redisTemplate.opsForZSet()
.reverseRangeWithScores(key, 0, 0);
if (set != null && !set.isEmpty()) {
return set.iterator().next().getScore();
}
return null;
} catch (Exception e) {
log.error("获取ZSet最大分数失败 key: {}, error: {}", key, e.getMessage());
return null;
}
}
// ============================== Hash(Map) 数据类型详细操作 ==============================
/**
* 批量设置Hash值(如果字段不存在则设置)
*/
public void setHashIfAbsent(String key, Map<String, Object> map) {
try {
for (Map.Entry<String, Object> entry : map.entrySet()) {
redisTemplate.opsForHash().putIfAbsent(key, entry.getKey(), entry.getValue());
}
log.info("Hash批量设置(不存在才设置)成功 key: {}, map: {}", key, map);
} catch (Exception e) {
log.error("Hash批量设置(不存在才设置)失败 key: {}, error: {}", key, e.getMessage());
}
}
/**
* 增加Hash中某个字段的数值(整型)
*/
public Long incrementHash(String key, String hashKey, long delta) {
try {
Long newValue = redisTemplate.opsForHash().increment(key, hashKey, delta);
log.info("Hash字段增加成功 key: {}, hashKey: {}, delta: {}, newValue: {}",
key, hashKey, delta, newValue);
return newValue;
} catch (Exception e) {
log.error("Hash字段增加失败 key: {}, hashKey: {}, error: {}",
key, hashKey, e.getMessage());
return null;
}
}
/**
* 增加Hash中某个字段的数值(浮点型)
*/
public Double incrementHash(String key, String hashKey, double delta) {
try {
Double newValue = redisTemplate.opsForHash().increment(key, hashKey, delta);
log.info("Hash字段增加(浮点)成功 key: {}, hashKey: {}, delta: {}, newValue: {}",
key, hashKey, delta, newValue);
return newValue;
} catch (Exception e) {
log.error("Hash字段增加(浮点)失败 key: {}, hashKey: {}, error: {}",
key, hashKey, e.getMessage());
return null;
}
}
/**
* 获取Hash中多个字段的值
*/
public List<Object> getMultiHash(String key, List<String> hashKeys) {
try {
return redisTemplate.opsForHash().multiGet(key, Arrays.asList(hashKeys.toArray()));
} catch (Exception e) {
log.error("获取Hash多个字段失败 key: {}, hashKeys: {}, error: {}",
key, hashKeys, e.getMessage());
return Collections.emptyList();
}
}
/**
* 获取Hash的长度(字段数量)
*/
public Long getHashLength(String key) {
try {
return redisTemplate.opsForHash().size(key);
} catch (Exception e) {
log.error("获取Hash长度失败 key: {}, error: {}", key, e.getMessage());
return 0L;
}
}
/**
* 批量删除Hash中的字段
*/
public Long deleteHashFields(String key, List<String> hashKeys) {
try {
return redisTemplate.opsForHash().delete(key, hashKeys.toArray());
} catch (Exception e) {
log.error("批量删除Hash字段失败 key: {}, hashKeys: {}, error: {}",
key, hashKeys, e.getMessage());
return 0L;
}
}
/**
* 获取Hash中的所有字段和值
*/
public Map<String, Object> getHashAllAsString(String key) {
try {
Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
Map<String, Object> result = new HashMap<>();
for (Map.Entry<Object, Object> entry : entries.entrySet()) {
result.put(entry.getKey().toString(), entry.getValue());
}
return result;
} catch (Exception e) {
log.error("获取Hash所有字段和值失败 key: {}, error: {}", key, e.getMessage());
return Collections.emptyMap();
}
}
/**
* 扫描Hash中的字段(用于大数据量)
*/
public Map<String, Object> scanHash(String key, String pattern, int count) {
try {
Map<String, Object> result = new HashMap<>();
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash()
.scan(key, ScanOptions.scanOptions().match(pattern).count(count).build());
while (cursor.hasNext()) {
Map.Entry<Object, Object> entry = cursor.next();
result.put(entry.getKey().toString(), entry.getValue());
}
cursor.close();
return result;
} catch (Exception e) {
log.error("扫描Hash失败 key: {}, pattern: {}, error: {}", key, pattern, e.getMessage());
return Collections.emptyMap();
}
}
5.控制器类中的实际调用示例
package com.example.redis.controller;
import com.example.redis.service.RedisDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@Slf4j
@RestController
@RequestMapping("/redis/data")
public class RedisDataController {
@Autowired
private RedisDataService redisDataService;
// ============================== Set 操作示例 ==============================
/**
* 示例1:用户标签系统
*/
@PostMapping("/set/userTags")
public Map<String, Object> setUserTags() {
Map<String, Object> result = new HashMap<>();
// 用户1的标签
redisDataService.addToSetWithExpire("user:tags:1001", 86400,
"VIP", "活跃用户", "北京", "程序员", "技术爱好者");
// 用户2的标签
redisDataService.addToSetWithExpire("user:tags:1002", 86400,
"新用户", "上海", "设计师", "艺术爱好者");
// 用户3的标签
redisDataService.addToSetWithExpire("user:tags:1003", 86400,
"VIP", "广州", "产品经理", "技术爱好者");
// 获取共同标签
Set<Object> commonTags = redisDataService.setIntersect("user:tags:1001", "user:tags:1003");
result.put("用户1和用户3的共同标签", commonTags);
// 获取所有标签
Set<Object> allTags = redisDataService.setUnion(
Arrays.asList("user:tags:1001", "user:tags:1002", "user:tags:1003"));
result.put("所有用户的标签", allTags);
// 随机推荐标签
Object randomTag = redisDataService.getRandomSetMember("user:tags:1001");
result.put("为用户1随机推荐的标签", randomTag);
return result;
}
/**
* 示例2:抽奖系统
*/
@PostMapping("/set/lottery")
public Map<String, Object> lotterySystem() {
Map<String, Object> result = new HashMap<>();
// 添加抽奖参与者
String[] participants = {
"张三", "李四", "王五", "赵六", "钱七",
"孙八", "周九", "吴十", "郑十一", "王十二"
};
redisDataService.addToSetWithExpire("lottery:2023:participants", 3600, (Object[]) participants);
// 随机抽取3名获奖者(不重复)
List<Object> winners = redisDataService.popRandomSetMembers("lottery:2023:participants", 3);
result.put("获奖者", winners);
// 查看剩余参与者
Set<Object> remaining = redisDataService.getAllSetMembers("lottery:2023:participants");
result.put("剩余参与者", remaining);
return result;
}
/**
* 示例3:共同关注/好友系统
*/
@PostMapping("/set/social")
public Map<String, Object> socialSystem() {
Map<String, Object> result = new HashMap<>();
// 用户A的关注列表
redisDataService.addToSet("user:follow:1001", "user:1002", "user:1003", "user:1004", "user:1005");
// 用户B的关注列表
redisDataService.addToSet("user:follow:1002", "user:1001", "user:1003", "user:1006", "user:1007");
// 用户C的关注列表
redisDataService.addToSet("user:follow:1003", "user:1001", "user:1002", "user:1004", "user:1008");
// 共同关注
Set<Object> commonFollow = redisDataService.setIntersect("user:follow:1001", "user:follow:1002");
result.put("用户A和用户B的共同关注", commonFollow);
// 可能认识的人(B关注了但A没关注的)
Set<Object> recommendFollow = redisDataService.setDifference("user:follow:1002", "user:follow:1001");
result.put("推荐给用户A关注的人", recommendFollow);
// 相互关注(A关注B且B关注A)
boolean isMutual = redisDataService.isSetMember("user:follow:1001", "user:1002") &&
redisDataService.isSetMember("user:follow:1002", "user:1001");
result.put("用户A和用户B是否相互关注", isMutual);
return result;
}
// ============================== ZSet 操作示例 ==============================
/**
* 示例1:游戏排行榜
*/
@PostMapping("/zset/gameRank")
public Map<String, Object> gameRankingSystem() {
Map<String, Object> result = new HashMap<>();
// 初始化玩家分数
Map<Object, Double> playerScores = new HashMap<>();
playerScores.put("player:1001", 1500.0);
playerScores.put("player:1002", 2300.0);
playerScores.put("player:1003", 1800.0);
playerScores.put("player:1004", 1950.0);
playerScores.put("player:1005", 2100.0);
redisDataService.addToZSet("game:rank:league1", playerScores);
// 更新分数(玩家赢得比赛)
Double newScore = redisDataService.incrementZSetScore("game:rank:league1", "player:1001", 50.5);
result.put("玩家1001新分数", newScore);
// 获取前三名
Set<ZSetOperations.TypedTuple<Object>> top3 = redisDataService
.getZSetRangeWithScores("game:rank:league1", 0, 2);
result.put("排行榜前三名", formatZSetResult(top3));
// 获取玩家排名
Long rank = redisDataService.getZSetReverseRank("game:rank:league1", "player:1001");
result.put("玩家1001的排名", rank != null ? rank + 1 : "未上榜");
// 获取分数段玩家(1800-2200分)
Set<ZSetOperations.TypedTuple<Object>> midRange = redisDataService
.getZSetRangeByScoreWithScores("game:rank:league1", 1800, 2200);
result.put("1800-2200分段的玩家", formatZSetResult(midRange));
return result;
}
/**
* 示例2:热门商品排行榜
*/
@PostMapping("/zset/productHotRank")
public Map<String, Object> productHotRanking() {
Map<String, Object> result = new HashMap<>();
// 模拟商品热度数据(热度 = 点击量 * 0.3 + 销量 * 0.7)
Map<Object, Double> productHeat = new HashMap<>();
productHeat.put("product:1001", 850.5); // 热度值
productHeat.put("product:1002", 1200.3);
productHeat.put("product:1003", 750.2);
productHeat.put("product:1004", 980.7);
productHeat.put("product:1005", 650.1);
productHeat.put("product:1006", 1100.8);
redisDataService.addToZSet("product:heat:rank", productHeat);
// 商品1001增加热度(用户点击)
redisDataService.incrementZSetScore("product:heat:rank", "product:1001", 15.5);
// 商品1002减少热度(热度衰减)
redisDataService.decrementZSetScore("product:heat:rank", "product:1002", 20.0);
// 获取热门商品Top5
Set<ZSetOperations.TypedTuple<Object>> top5 = redisDataService
.getZSetReverseRangeWithScores("product:heat:rank", 0, 4);
result.put("热门商品Top5", formatZSetResult(top5));
// 获取热度范围
Double minHeat = redisDataService.getZSetMinScore("product:heat:rank");
Double maxHeat = redisDataService.getZSetMaxScore("product:heat:rank");
result.put("最低热度", minHeat);
result.put("最高热度", maxHeat);
// 分页获取商品(第2页,每页2个)
Set<ZSetOperations.TypedTuple<Object>> page2 = redisDataService
.getZSetRangeByScoreWithScores("product:heat:rank", 0, Double.MAX_VALUE, 2, 2);
result.put("第二页商品", formatZSetResult(page2));
return result;
}
/**
* 示例3:延时任务队列
*/
@PostMapping("/zset/delayQueue")
public Map<String, Object> delayQueueExample() {
Map<String, Object> result = new HashMap<>();
long currentTime = System.currentTimeMillis();
// 添加延时任务(score为执行时间戳)
redisDataService.addToZSet("system:delay:queue", "task:order:1001", currentTime + 5000); // 5秒后执行
redisDataService.addToZSet("system:delay:queue", "task:order:1002", currentTime + 10000); // 10秒后执行
redisDataService.addToZSet("system:delay:queue", "task:notify:1001", currentTime + 3000); // 3秒后执行
redisDataService.addToZSet("system:delay:queue", "task:clean:cache", currentTime + 60000); // 60秒后执行
// 模拟检查到期任务
Set<ZSetOperations.TypedTuple<Object>> dueTasks = redisDataService
.getZSetRangeByScoreWithScores("system:delay:queue", 0, currentTime + 6000);
result.put("6秒内到期的任务", formatZSetResult(dueTasks));
// 移除已处理的任务
if (!dueTasks.isEmpty()) {
List<Object> tasksToRemove = new ArrayList<>();
for (ZSetOperations.TypedTuple<Object> tuple : dueTasks) {
tasksToRemove.add(tuple.getValue());
}
redisDataService.removeFromZSet("system:delay:queue", tasksToRemove.toArray());
result.put("已移除的任务", tasksToRemove);
}
return result;
}
// ============================== Hash(Map) 操作示例 ==============================
/**
* 示例1:用户会话管理
*/
@PostMapping("/hash/userSession")
public Map<String, Object> userSessionManagement() {
Map<String, Object> result = new HashMap<>();
// 用户1的会话信息
Map<String, Object> session1 = new HashMap<>();
session1.put("userId", "1001");
session1.put("username", "张三");
session1.put("loginTime", System.currentTimeMillis());
session1.put("lastActivity", System.currentTimeMillis());
session1.put("ip", "192.168.1.100");
session1.put("userAgent", "Mozilla/5.0");
session1.put("token", "abc123xyz");
redisDataService.setHashAll("session:user:1001", session1);
// 更新最后活动时间
redisDataService.incrementHash("session:user:1001", "lastActivity", System.currentTimeMillis());
// 获取会话信息
Map<String, Object> sessionInfo = redisDataService.getHashAllAsString("session:user:1001");
result.put("用户会话信息", sessionInfo);
// 获取多个字段
List<String> fields = Arrays.asList("username", "loginTime", "ip");
List<Object> fieldValues = redisDataService.getMultiHash("session:user:1001", fields);
result.put("指定字段值", fieldValues);
// 扫描会话(查找特定模式的会话)
Map<String, Object> scannedSessions = redisDataService.scanHash("session:user:1001", "*Time*", 10);
result.put("扫描到的Time相关字段", scannedSessions);
return result;
}
/**
* 示例2:商品库存管理
*/
@PostMapping("/hash/productInventory")
public Map<String, Object> productInventorySystem() {
Map<String, Object> result = new HashMap<>();
// 初始化商品库存
Map<String, Object> inventory = new HashMap<>();
inventory.put("product:1001:stock", 150);
inventory.put("product:1001:price", 299.99);
inventory.put("product:1001:name", "iPhone 14");
inventory.put("product:1001:color", "黑色");
inventory.put("product:1002:stock", 80);
inventory.put("product:1002:price", 899.99);
inventory.put("product:1002:name", "MacBook Pro");
inventory.put("product:1002:color", "银色");
redisDataService.setHashAll("inventory:products", inventory);
// 扣减库存(原子操作)
Long remainingStock = redisDataService.incrementHash("inventory:products", "product:1001:stock", -5);
result.put("商品1001扣减5个库存后剩余", remainingStock);
// 增加库存
Long newStock = redisDataService.incrementHash("inventory:products", "product:1002:stock", 20);
result.put("商品1002增加20个库存后总数", newStock);
// 获取商品1001的所有信息
Map<String, Object> product1001 = new HashMap<>();
product1001.put("stock", redisDataService.getHash("inventory:products", "product:1001:stock"));
product1001.put("price", redisDataService.getHash("inventory:products", "product:1001:price"));
product1001.put("name", redisDataService.getHash("inventory:products", "product:1001:name"));
result.put("商品1001详情", product1001);
// 获取Hash大小
Long hashSize = redisDataService.getHashLength("inventory:products");
result.put("库存Hash中的字段数量", hashSize);
return result;
}
/**
* 示例3:配置管理中心
*/
@PostMapping("/hash/configCenter")
public Map<String, Object> configCenterExample() {
Map<String, Object> result = new HashMap<>();
// 系统配置
Map<String, Object> systemConfig = new HashMap<>();
systemConfig.put("app.name", "电商平台");
systemConfig.put("app.version", "2.0.1");
systemConfig.put("api.timeout", "30000");
systemConfig.put("cache.enabled", "true");
systemConfig.put("cache.ttl", "3600");
systemConfig.put("log.level", "INFO");
systemConfig.put("max.connections", "100");
systemConfig.put("feature.flag.newUI", "false");
redisDataService.setHashAll("config:system", systemConfig);
// 动态更新配置(如果不存在则设置)
Map<String, Object> newConfigs = new HashMap<>();
newConfigs.put("api.retry.count", "3");
newConfigs.put("feature.flag.newUI", "true"); // 这个已存在,不会更新
newConfigs.put("backup.enabled", "false");
redisDataService.setHashIfAbsent("config:system", newConfigs);
// 获取所有配置
Map<String, Object> allConfigs = redisDataService.getHashAllAsString("config:system");
result.put("所有系统配置", allConfigs);
// 批量删除配置
List<String> configsToRemove = Arrays.asList("feature.flag.newUI", "backup.enabled");
Long deletedCount = redisDataService.deleteHashFields("config:system", configsToRemove);
result.put("删除的配置数量", deletedCount);
// 更新后的配置
Map<String, Object> updatedConfigs = redisDataService.getHashAllAsString("config:system");
result.put("更新后的配置", updatedConfigs);
return result;
}
/**
* 示例4:购物车实现
*/
@PostMapping("/hash/shoppingCart")
public Map<String, Object> shoppingCartImplementation() {
Map<String, Object> result = new HashMap<>();
// 用户1001的购物车
Map<String, Object> cartItems = new HashMap<>();
cartItems.put("product:1001", "2"); // 商品ID: 数量
cartItems.put("product:1002", "1");
cartItems.put("product:1003", "3");
redisDataService.setHashAll("cart:user:1001", cartItems);
// 添加商品到购物车
Long newQuantity = redisDataService.incrementHash("cart:user:1001", "product:1001", 1);
result.put("商品1001增加1个后数量", newQuantity);
// 减少商品数量
Long updatedQuantity = redisDataService.incrementHash("cart:user:1001", "product:1003", -1);
result.put("商品1003减少1个后数量", updatedQuantity);
// 获取购物车所有商品
Map<String, Object> cart = redisDataService.getHashAllAsString("cart:user:1001");
result.put("购物车内容", cart);
// 获取购物车商品总数
Long totalItems = 0L;
for (Object quantity : cart.values()) {
totalItems += Long.parseLong(quantity.toString());
}
result.put("购物车商品总数", totalItems);
// 清空部分商品
List<String> itemsToRemove = Arrays.asList("product:1002");
redisDataService.deleteHashFields("cart:user:1001", itemsToRemove);
// 清空后的购物车
Map<String, Object> clearedCart = redisDataService.getHashAllAsString("cart:user:1001");
result.put("清空部分商品后的购物车", clearedCart);
return result;
}
// ============================== 工具方法 ==============================
/**
* 格式化ZSet结果
*/
private List<Map<String, Object>> formatZSetResult(Set<ZSetOperations.TypedTuple<Object>> tuples) {
List<Map<String, Object>> result = new ArrayList<>();
for (ZSetOperations.TypedTuple<Object> tuple : tuples) {
Map<String, Object> item = new HashMap<>();
item.put("value", tuple.getValue());
item.put("score", tuple.getScore());
result.add(item);
}
return result;
}
/**
* 获取ZSet反向排名范围(带分数)
*/
private Set<ZSetOperations.TypedTuple<Object>> getZSetReverseRangeWithScores(String key, long start, long end) {
try {
return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
} catch (Exception e) {
log.error("获取ZSet反向范围带分数失败 key: {}, start: {}, end: {}, error: {}",
key, start, end, e.getMessage());
return Collections.emptySet();
}
}
}
6.测试工具类
package com.example.redis.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
public class RedisDataTypeDemo {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 演示所有Redis数据类型的操作
*/
public void demoAllDataTypes() {
System.out.println("========== Redis 数据类型操作演示 ==========");
// 1. String 类型演示
demoStringType();
// 2. List 类型演示
demoListType();
// 3. Hash (Map) 类型演示
demoHashType();
// 4. Set 类型演示
demoSetType();
// 5. ZSet 类型演示
demoZSetType();
System.out.println("========== 演示结束 ==========");
}
private void demoStringType() {
System.out.println("\n--- String 类型演示 ---");
// 设置字符串
redisTemplate.opsForValue().set("demo:string:key1", "Hello Redis");
redisTemplate.opsForValue().set("demo:string:counter", "100");
// 获取字符串
String value = (String) redisTemplate.opsForValue().get("demo:string:key1");
System.out.println("String值: " + value);
// 递增操作
Long newValue = redisTemplate.opsForValue().increment("demo:string:counter", 50);
System.out.println("递增后: " + newValue);
// 设置过期时间
redisTemplate.opsForValue().set("demo:string:temp", "临时数据", 60);
}
private void demoListType() {
System.out.println("\n--- List 类型演示 ---");
// 从右侧插入
redisTemplate.opsForList().rightPush("demo:list:messages", "消息1");
redisTemplate.opsForList().rightPush("demo:list:messages", "消息2");
redisTemplate.opsForList().rightPush("demo:list:messages", "消息3");
// 从左侧插入
redisTemplate.opsForList().leftPush("demo:list:messages", "紧急消息");
// 获取列表范围
System.out.println("所有消息: " + redisTemplate.opsForList().range("demo:list:messages", 0, -1));
// 获取列表长度
Long size = redisTemplate.opsForList().size("demo:list:messages");
System.out.println("消息数量: " + size);
// 获取指定索引的值
Object firstMessage = redisTemplate.opsForList().index("demo:list:messages", 0);
System.out.println("第一条消息: " + firstMessage);
}
private void demoHashType() {
System.out.println("\n--- Hash (Map) 类型演示 ---");
// 设置Hash值
redisTemplate.opsForHash().put("demo:hash:user:1001", "name", "张三");
redisTemplate.opsForHash().put("demo:hash:user:1001", "age", "25");
redisTemplate.opsForHash().put("demo:hash:user:1001", "email", "zhangsan@example.com");
// 获取Hash值
String name = (String) redisTemplate.opsForHash().get("demo:hash:user:1001", "name");
System.out.println("用户名: " + name);
// 获取所有字段
System.out.println("所有字段: " + redisTemplate.opsForHash().entries("demo:hash:user:1001"));
// 检查字段是否存在
boolean hasEmail = redisTemplate.opsForHash().hasKey("demo:hash:user:1001", "email");
System.out.println("是否有email字段: " + hasEmail);
// 增加数值字段
redisTemplate.opsForHash().increment("demo:hash:user:1001", "age", 1);
System.out.println("增加年龄后: " + redisTemplate.opsForHash().get("demo:hash:user:1001", "age"));
}
private void demoSetType() {
System.out.println("\n--- Set 类型演示 ---");
// 添加元素
redisTemplate.opsForSet().add("demo:set:tags", "Java", "Redis", "Spring", "MySQL");
redisTemplate.opsForSet().add("demo:set:tags", "Redis", "NoSQL"); // 重复元素不会被添加
// 获取所有元素
Set<Object> tags = redisTemplate.opsForSet().members("demo:set:tags");
System.out.println("所有标签: " + tags);
// 随机获取元素
Object randomTag = redisTemplate.opsForSet().randomMember("demo:set:tags");
System.out.println("随机标签: " + randomTag);
// 检查元素是否存在
boolean hasJava = redisTemplate.opsForSet().isMember("demo:set:tags", "Java");
System.out.println("是否包含Java: " + hasJava);
// 集合大小
Long size = redisTemplate.opsForSet().size("demo:set:tags");
System.out.println("标签数量: " + size);
}
private void demoZSetType() {
System.out.println("\n--- ZSet 类型演示 ---");
// 添加带分数的元素
redisTemplate.opsForZSet().add("demo:zset:scores", "玩家A", 85.5);
redisTemplate.opsForZSet().add("demo:zset:scores", "玩家B", 92.0);
redisTemplate.opsForZSet().add("demo:zset:scores", "玩家C", 78.5);
redisTemplate.opsForZSet().add("demo:zset:scores", "玩家D", 95.0);
// 按分数升序获取
System.out.println("升序排名: " + redisTemplate.opsForZSet().range("demo:zset:scores", 0, -1));
// 按分数降序获取
System.out.println("降序排名: " + redisTemplate.opsForZSet().reverseRange("demo:zset:scores", 0, -1));
// 获取分数
Double score = redisTemplate.opsForZSet().score("demo:zset:scores", "玩家B");
System.out.println("玩家B的分数: " + score);
// 获取排名(从0开始)
Long rank = redisTemplate.opsForZSet().rank("demo:zset:scores", "玩家B");
System.out.println("玩家B的排名: " + (rank != null ? rank + 1 : "未上榜"));
// 增加分数
Double newScore = redisTemplate.opsForZSet().incrementScore("demo:zset:scores", "玩家C", 10.0);
System.out.println("玩家C增加分数后: " + newScore);
}
}
7.启动类中的演示代码
package com.example.redis;
import com.example.redis.util.RedisDataTypeDemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedisDemoApplication implements CommandLineRunner {
@Autowired
private RedisDataTypeDemo redisDataTypeDemo;
public static void main(String[] args) {
SpringApplication.run(RedisDemoApplication.class, args);
System.out.println("Redis 数据类型演示应用启动成功!");
System.out.println("访问以下地址进行测试:");
System.out.println("1. Set操作示例: http://localhost:8080/redis/data/set/userTags");
System.out.println("2. ZSet操作示例: http://localhost:8080/redis/data/zset/gameRank");
System.out.println("3. Hash操作示例: http://localhost:8080/redis/data/hash/userSession");
}
@Override
public void run(String... args) throws Exception {
// 启动时演示所有数据类型
redisDataTypeDemo.demoAllDataTypes();
}
}
8.使用示例说明
1. Set 类型实际应用场景
用户标签系统:
bash
POST http://localhost:8080/redis/data/set/userTags
-
存储用户标签
-
查找共同标签
-
标签推荐
抽奖系统:
bash
POST http://localhost:8080/redis/data/set/lottery
-
添加参与者
-
随机抽取获奖者
-
移除已抽中者
2. ZSet 类型实际应用场景
游戏排行榜:
bash
POST http://localhost:8080/redis/data/zset/gameRank
-
存储玩家分数
-
实时更新分数
-
获取排行榜
延时任务队列:
bash
POST http://localhost:8080/redis/data/zset/delayQueue
-
按执行时间排序
-
定时检查到期任务
-
原子性移除任务
3. Hash 类型实际应用场景
用户会话管理:
bash
POST http://localhost:8080/redis/data/hash/userSession
-
存储用户会话信息
-
原子更新字段
-
批量获取字段
购物车实现:
bash
POST http://localhost:8080/redis/data/hash/shoppingCart
-
商品ID作为field
-
数量作为value
-
原子增减数量
这些示例覆盖了Redis所有主要数据类型的实际应用场景,展示了如何在Spring Boot中操作这些数据类型。每个示例都包含了完整的业务逻辑和实际使用场景。