目录
- 1.项目依赖
- 2.动态创建 RedisTemplate实例
- 3.创建Redis操作服务类
- 4.创建控制器
- 5.测试
在 Spring Boot 项目中使用RedisTemplate实现:
Redis 数据库迁移
,本质上就是将一个 Redis 数据库中的数据复制到另一个 Redis 数据库中。
Redis 修改键名
,实际上 Redis 并没有直接提供修改键名的方法,但可以通过先复制原键的值到新键,然后删除原键的方式来间接实现键的修改
以下是详细的实现步骤:
1.项目依赖
首先,确保你的 Spring Boot 项目中已经添加了 Spring Data Redis 依赖。
在pom.xml中添加以下依赖:
<!--redis依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.4.6</version>
</dependency>
2.动态创建 RedisTemplate实例
创建一个工具类,用于根据传入的数据库配置信息动态创建 RedisTemplate 实例。
package com.example.redisdemo.utils;import io.micrometer.common.util.StringUtils;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;/*** redis工具类:根据传入的数据库配置信息动态创建 RedisTemplate 实例* @author qzz* @date 2025/3/4*/
@Component
public class RedisTemplateFactory {private String REDIS_HOST = "localhost";private Integer REDIS_PORT = 6379;private String REDIS_PASSWORD = "";/*** 根据传入的数据库配置信息动态创建 RedisTemplate 实例* @param database* @return*/public RedisTemplate<String, Object> createRedisTemplate(int database) {return createRedisTemplate(REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, database);}/*** 根据传入的数据库配置信息动态创建 RedisTemplate 实例* @param host* @param port* @param password* @param database* @return*/public RedisTemplate<String, Object> createRedisTemplate(String host, int port, String password, int database) {RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();config.setHostName(host);config.setPort(port);if(StringUtils.isNotEmpty(password)){config.setPassword(password);}config.setDatabase(database);LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);connectionFactory.afterPropertiesSet();RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// 设置键的序列化器template.setKeySerializer(new StringRedisSerializer());// 设置值的序列化器template.setValueSerializer(new StringRedisSerializer());// 设置哈希键的序列化器template.setHashKeySerializer(new StringRedisSerializer());// 设置哈希值的序列化器template.setHashValueSerializer(new StringRedisSerializer());template.afterPropertiesSet();return template;}
}
3.创建Redis操作服务类
package com.example.redisdemo.service.impl;import com.example.redisdemo.model.ResultJson;
import com.example.redisdemo.request.RedisDBRequestJson;
import com.example.redisdemo.request.RedisKeyRequestJson;
import com.example.redisdemo.service.IRedisOperationService;
import com.example.redisdemo.utils.RedisTemplateFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** redis 迁移数据库、修改键名操作* @author qzz* @date 2025/3/3*/
@Slf4j
@Service
public class RedisOperationServiceImpl implements IRedisOperationService {@Autowiredprivate RedisTemplateFactory redisTemplateFactory;/*** redis数据库迁移 --- 数据库只动态修改 database* @param redisDBRequestJson* @return*/@Override@Transactional(rollbackFor = Exception.class)public ResultJson transferRedisDB(RedisDBRequestJson redisDBRequestJson) {try {//redis源数据库RedisTemplate<String, Object> sourceRedisTemplate = redisTemplateFactory.createRedisTemplate(redisDBRequestJson.getSourceDatabase());//redis目标数据库RedisTemplate<String, Object> targetRedisTemplate = redisTemplateFactory.createRedisTemplate(redisDBRequestJson.getTargetDatabase());// 获取源数据库中的所有键Set<String> keys = sourceRedisTemplate.keys("*");if (keys != null) {for (String key : keys) {//复制键及其值 到 目标RedisTemplatecopyKey(key, sourceRedisTemplate, targetRedisTemplate);}}}catch (Exception e){log.error("Redis数据库迁移失败", e);return ResultJson.fail(500,"Redis数据库迁移失败");}return ResultJson.success();}/*** 复制键及其值 到 目标RedisTemplate* @param sourceKey 源键* @param sourceRedisTemplate 源RedisTemplate* @param targetRedisTemplate 目标RedisTemplate*/private static void copyKey(String sourceKey, RedisTemplate<String, Object> sourceRedisTemplate, RedisTemplate<String, Object> targetRedisTemplate) {copyKey(sourceKey, sourceKey, sourceRedisTemplate, targetRedisTemplate);}/*** 复制键及其值 到 目标RedisTemplate,并可以指定目标键名* @param sourceKey 源键* @param targetKey 目标键* @param sourceRedisTemplate 源RedisTemplate* @param targetRedisTemplate 目标RedisTemplate*/private static void copyKey(String sourceKey, String targetKey, RedisTemplate<String, Object> sourceRedisTemplate, RedisTemplate<String, Object> targetRedisTemplate) {// 获取键的类型String type = sourceRedisTemplate.type(sourceKey).code();switch (type){case "string"://处理字符串类型的值String value = (String) sourceRedisTemplate.opsForValue().get(sourceKey);targetRedisTemplate.opsForValue().set(targetKey, value);break;case "list":Long listSize = sourceRedisTemplate.opsForList().size(sourceKey);for (int i = 0; i < listSize; i++) {String listValue = (String) sourceRedisTemplate.opsForList().index(sourceKey, i);targetRedisTemplate.opsForList().rightPush(targetKey, listValue);}break;case "set":// 处理集合类型的数据Set<Object> setMembers = sourceRedisTemplate.opsForSet().members(sourceKey);if (setMembers != null) {for (Object member : setMembers) {targetRedisTemplate.opsForSet().add(targetKey, member);}}break;case "zset":// 处理有序集合类型的数据Set<Object> zsetMembers = sourceRedisTemplate.opsForZSet().range(sourceKey, 0, -1);if (zsetMembers != null) {for (Object member : zsetMembers) {Double score = sourceRedisTemplate.opsForZSet().score(sourceKey, member);targetRedisTemplate.opsForZSet().add(targetKey, member, score);}}break;case "hash":// 处理哈希类型的数据Map<Object, Object> hashEntries = sourceRedisTemplate.opsForHash().entries(sourceKey);if (!hashEntries.isEmpty()) {targetRedisTemplate.opsForHash().putAll(targetKey, hashEntries);}break;default:System.out.println("Unsupported data type: " + type);}}/*** redis 修改键名: 实现 Redis 键的修改,实际上 Redis 并没有直接提供修改键名的方法,但可以通过先复制原键的值到新键,然后删除原键的方式来间接实现键的修改* @param redisDBRequestJson* @return*/@Override@Transactional(rollbackFor = Exception.class)public ResultJson updateRedisKey(RedisDBRequestJson redisDBRequestJson) {try {//redis目标数据库RedisTemplate<String, Object> targetRedisTemplate = redisTemplateFactory.createRedisTemplate(redisDBRequestJson.getTargetDatabase());//遍历key列表for (RedisKeyRequestJson redisKey : redisDBRequestJson.getRedisKeyList()) {if (targetRedisTemplate.hasKey(redisKey.getSourceKey())) {String sourceKey = redisKey.getSourceKey();String targetKey = redisKey.getTargetKey();//1.复制键及其值 到新键copyKey(sourceKey, targetKey, targetRedisTemplate, targetRedisTemplate);//2.获取原键的过期时间Long expire = targetRedisTemplate.getExpire(sourceKey, TimeUnit.SECONDS);if (expire != null && expire > 0) {// 设置新键的过期时间targetRedisTemplate.expire(targetKey, expire, TimeUnit.SECONDS);}//3.删除原键targetRedisTemplate.delete(sourceKey);}}}catch (Exception e){log.error("Redis 修改键名失败", e);return ResultJson.fail(500,"Redis 修改键名失败");}return ResultJson.success();}/*** redis数据库迁移 --- 数据库动态修改 host、password、database* @param requestJson* @return*/@Override@Transactional(rollbackFor = Exception.class)public ResultJson transferRedisDBByDynamics(RedisDBRequestJson requestJson) {try {//redis源数据库RedisTemplate<String, Object> sourceRedisTemplate = redisTemplateFactory.createRedisTemplate(requestJson.getSourceHost(), requestJson.getSourcePort(), requestJson.getSourcePassword(), requestJson.getSourceDatabase());//redis目标数据库RedisTemplate<String, Object> targetRedisTemplate = redisTemplateFactory.createRedisTemplate(requestJson.getTargetHost(), requestJson.getTargetPort(), requestJson.getTargetPassword(), requestJson.getTargetDatabase());// 获取源数据库中的所有键Set<String> keys = sourceRedisTemplate.keys("*");if (keys != null) {for (String key : keys) {//复制键及其值 到 目标RedisTemplatecopyKey(key, sourceRedisTemplate, targetRedisTemplate);}}}catch (Exception e){log.error("Redis数据库迁移失败", e);return ResultJson.fail(500,"Redis数据库迁移失败");}return ResultJson.success();}
}
4.创建控制器
创建一个控制器类,用于接收客户端传递的数据库配置信息,并进行数据迁移、修改键名的操作。
package com.example.redisdemo.controller;import com.example.redisdemo.model.ResultJson;
import com.example.redisdemo.request.RedisDBRequestJson;
import com.example.redisdemo.service.IRedisOperationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;/*** redis 迁移数据库、修改键名操作* @author qzz* @date 2025/3/3*/
@RestController
public class RedisController {@Autowiredprivate IRedisOperationService operationService;/*** redis数据库迁移 --- 数据库只动态修改 database* @return*/@PostMapping("/api/{version}/redis-migration/")public ResultJson transferRedisDB(@RequestBody RedisDBRequestJson redisDBRequestJson) {return operationService.transferRedisDB(redisDBRequestJson);}/*** redis 修改键名* @return*/@PostMapping("/api/{version}/redis/rename-key/")public ResultJson updateRedisKey(@RequestBody RedisDBRequestJson redisDBRequestJson) {return operationService.updateRedisKey(redisDBRequestJson);}/*** redis数据库迁移 --- 数据库动态修改 host、password、database* @return*/@PostMapping("/api/{version}/redis-migration/dynamics/")public ResultJson transferRedisDBByDynamics(@RequestBody RedisDBRequestJson redisDBRequestJson) {return operationService.transferRedisDBByDynamics(redisDBRequestJson);}}
5.测试
启动 Spring Boot 应用后,可以通过以下 URL 发起请求进行数据迁移:
修改键名: