本文目录导读:

- 项目依赖配置 (pom.xml)
- 配置文件 (application.yml)
- Redis配置类
- 实体类
- 服务类 - 涵盖各种操作场景
- Controller 测试接口
- Redis工具类封装
- 异常处理建议
- 常见问题及解决方案
下面我给你一个完整的Spring Data Redis实战案例,包含配置、基础操作、序列化配置、以及一些常见的业务场景,这个案例会覆盖你开发中最常用到的功能。
项目依赖配置 (pom.xml)
<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>
<!-- JSON序列化工具 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
配置文件 (application.yml)
spring:
redis:
host: localhost
port: 6379
password: # 如果没有密码可以为空
database: 0
timeout: 5000ms
lettuce:
pool:
max-active: 8 # 最大连接数
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: -1ms # 最大等待时间,-1表示不限制
Redis配置类
package com.example.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 factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用StringRedisSerializer来序列化和反序列化redis的key
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用GenericJackson2JsonRedisSerializer来序列化和反序列化redis的value
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
实体类
package com.example.entity;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String description;
private BigDecimal price;
private Integer stock;
private LocalDateTime createTime;
}
服务类 - 涵盖各种操作场景
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;
import com.example.entity.Product;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ObjectMapper objectMapper;
// ==================== 1. String 操作 ====================
/**
* 设置字符串值
*/
public void setString(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 设置带过期时间的字符串值
*/
public void setStringWithExpire(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
* 获取字符串值
*/
public Object getString(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 设置过期时间(秒)
*/
public void expire(String key, long seconds) {
redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
}
// ==================== 2. Hash 操作 ====================
/**
* 设置Hash值
*/
public void setHash(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
/**
* 获取Hash值
*/
public Object getHash(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
/**
* 批量设置Hash
*/
public void setHashAll(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
}
/**
* 获取整个Hash
*/
public Map<Object, Object> getHashAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
// ==================== 3. List 操作 ====================
/**
* 向列表头部添加元素
*/
public void pushToList(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}
/**
* 向列表尾部添加元素
*/
public void addToList(String key, Object value) {
redisTemplate.opsForList().rightPush(key, value);
}
/**
* 批量添加元素到列表尾部
*/
public void addAllToList(String key, List<Object> values) {
redisTemplate.opsForList().rightPushAll(key, values);
}
/**
* 获取列表元素(range查询)
*/
public List<Object> getList(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
/**
* 从列表中弹出头部元素
*/
public Object popFromList(String key) {
return redisTemplate.opsForList().leftPop(key);
}
// ==================== 4. Set 操作 ====================
/**
* 添加元素到Set
*/
public void addToSet(String key, Object... values) {
redisTemplate.opsForSet().add(key, values);
}
/**
* 获取Set所有元素
*/
public Set<Object> getSetMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 移除Set中的元素
*/
public void removeFromSet(String key, Object... values) {
redisTemplate.opsForSet().remove(key, values);
}
// ==================== 5. ZSet 操作 ====================
/**
* 添加元素到ZSet
*/
public void addToZSet(String key, Object value, double score) {
redisTemplate.opsForZSet().add(key, value, score);
}
/**
* 获取ZSet中的元素(按分数排序)
*/
public Set<Object> getZSetWithScore(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}
/**
* 获取ZSet排名(正序,从小到大)
*/
public Long getZSetRank(String key, Object value) {
return redisTemplate.opsForZSet().rank(key, value);
}
// ==================== 6. 通用操作 ====================
/**
* 删除key
*/
public Boolean delete(String key) {
return redisTemplate.delete(key);
}
/**
* 批量删除
*/
public Long delete(List<String> keys) {
return redisTemplate.delete(keys);
}
/**
* 判断key是否存在
*/
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* 获取key的剩余过期时间
*/
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
// ==================== 7. 业务场景:缓存商品信息 ====================
/**
* 缓存商品(存储整个对象)
*/
public void cacheProduct(Product product) {
String key = "product:" + product.getId();
// 设置缓存,过期时间为2小时
redisTemplate.opsForValue().set(key, product, 2, TimeUnit.HOURS);
}
/**
* 获取缓存的商品
*/
public Product getCachedProduct(Long productId) {
String key = "product:" + productId;
Object value = redisTemplate.opsForValue().get(key);
if (value instanceof Product) {
return (Product) value;
}
return null;
}
/**
* 缓存商品并设置条件(如果key不存在才设置)
*/
public Boolean cacheIfAbsent(String key, Product product) {
return redisTemplate.opsForValue().setIfAbsent(key, product, 1, TimeUnit.HOURS);
}
// ==================== 8. 分布式锁示例 ====================
/**
* 尝试获取分布式锁
*/
public Boolean tryLock(String lockKey, String requestId, long expireSeconds) {
// 使用setIfAbsent实现分布式锁
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId);
if (Boolean.TRUE.equals(result)) {
// 设置过期时间
redisTemplate.expire(lockKey, expireSeconds, TimeUnit.SECONDS);
}
return result;
}
/**
* 释放分布式锁
*/
public void releaseLock(String lockKey, String requestId) {
// 为了防止误删,可以添加Lua脚本进行判断
// 简单实现:直接删除(生产环境建议使用Lua脚本)
String currentValue = (String) redisTemplate.opsForValue().get(lockKey);
if (requestId.equals(currentValue)) {
redisTemplate.delete(lockKey);
}
}
}
Controller 测试接口
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.example.entity.Product;
import com.example.service.RedisService;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/redis")
public class RedisController {
@Autowired
private RedisService redisService;
/**
* 测试字符串操作
*/
@PostMapping("/string")
public String testString() {
// 基础字符串
redisService.setString("test:hello", "Hello Redis");
Object value = redisService.getString("test:hello");
// 带过期时间
redisService.setStringWithExpire("test:expire", "This will expire in 5 seconds", 5, java.util.concurrent.TimeUnit.SECONDS);
return "String测试结果: " + value;
}
/**
* 测试对象缓存
*/
@PostMapping("/product")
public String testProduct() {
// 创建商品
Product product = new Product();
product.setId(1L);
product.setName("iPhone 15");
product.setPrice(new BigDecimal("6999.00"));
product.setStock(100);
product.setCreateTime(LocalDateTime.now());
// 缓存商品
redisService.cacheProduct(product);
// 获取商品
Product cachedProduct = redisService.getCachedProduct(1L);
if (cachedProduct != null) {
return "缓存商品成功: " + cachedProduct.getName() + ", 价格: " + cachedProduct.getPrice();
}
return "缓存商品失败";
}
/**
* 测试Hash操作 - 模拟用户信息
*/
@PostMapping("/hash")
public String testHash() {
// 模拟用户信息
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("name", "张三");
userInfo.put("age", 25);
userInfo.put("email", "zhangsan@example.com");
// 存储为用户hash
redisService.setHashAll("user:1001", userInfo);
// 修改某个字段
redisService.setHash("user:1001", "age", 26);
// 获取整个hash
Map<Object, Object> result = redisService.getHashAll("user:1001");
return "Hash用户信息: " + result;
}
/**
* 测试列表操作
*/
@PostMapping("/list")
public String testList() {
// 创建一个任务队列
for (int i = 1; i <= 5; i++) {
redisService.addToList("task:queue", "Task-" + i);
}
// 获取列表长度
Long listSize = redisService.getList("task:queue", 0, -1).size();
// 弹出头部元素
Object firstTask = redisService.popFromList("task:queue");
// 查看剩余任务
List<Object> remainingTasks = redisService.getList("task:queue", 0, -1);
return "任务队列 - 初始大小: " + listSize + ", 弹出: " + firstTask + ", 剩余: " + remainingTasks;
}
/**
* 测试删除
*/
@DeleteMapping("/{key}")
public String deleteKey(@PathVariable String key) {
Boolean deleted = redisService.delete(key);
return deleted ? "删除成功: " + key : "删除失败或key不存在: " + key;
}
}
Redis工具类封装
package com.example.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Redis操作工具类
*/
@Component
public class RedisUtils {
@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) {
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
}
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
public Boolean setIfAbsent(String key, Object value) {
return redisTemplate.opsForValue().setIfAbsent(key, value);
}
// ==================== Hash操作 ====================
public void hSet(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
public Map<Object, Object> hGetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
// ==================== List操作 ====================
public void lPush(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}
public void rPush(String key, Object value) {
redisTemplate.opsForList().rightPush(key, value);
}
public Object lPop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
public Object rPop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
// ==================== 通用操作 ====================
public boolean delete(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
public long delete(String... keys) {
Long count = redisTemplate.delete(Arrays.asList(keys));
return count != null ? count : 0;
}
public boolean hasKey(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
public boolean expire(String key, long timeout) {
return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, TimeUnit.SECONDS));
}
}
异常处理建议
package com.example.exception;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RedisConnectionFailureException.class)
public String handleRedisConnectionFailure(RedisConnectionFailureException e) {
return "Redis连接失败,请检查Redis服务是否启动: " + e.getMessage();
}
@ExceptionHandler(SerializationException.class)
public String handleSerializationException(SerializationException e) {
return "Redis序列化异常: " + e.getMessage();
}
}
常见问题及解决方案
-
中文乱码问题:确保value序列化使用GenericJackson2JsonRedisSerializer或Jackson2JsonRedisSerializer。
-
对象序列化问题:实体类要实现Serializable接口。
-
Redis连接池耗尽:合理配置连接池参数,设置max-wait时间。
-
key设计规范:推荐使用"业务:模块:id"格式,如"product:info:1001"。
-
缓存穿透问题:使用setIfAbsent或者布隆过滤器。
这个案例覆盖了Spring Data Redis的大部分常用操作,你可以根据需要灵活使用,记得根据实际业务需求调整配置和操作方法!