Redis不支持原生前缀批量删除,DEL命令不接受通配符;Spring Boot默认用双冒号(::)拼接key导致匹配失败;应使用SCAN+UNLINK安全清理,禁用KEYS命令,并显式配置StringRedisSerializer避免序列化干扰。

Redis 本身没有原生的「按前缀批量删除」命令,DEL 只接受明确的 key 名,不支持通配符。所谓“删不掉前缀 key”,往往不是 Redis 不支持,而是你用的工具或框架在 key 生成阶段就埋了坑——比如 Spring Boot 默认用双冒号 :: 拼接 key,导致你在命令行里搜 user: 根本匹配不到实际存储的 user::123。
Spring Boot 的 RedisTemplate 默认 key 命名含 ::
Spring Boot 2.x+ 默认使用 StringRedisTemplate 或 RedisTemplate 时,若未自定义 RedisCacheConfiguration,key 会自动加上双冒号。例如:
你代码里写 redisTemplate.opsForValue().set("user:1001", "data"),实际存进 Redis 的 key 是 user::1001(注意中间两个冒号)。
这时候你在 redis-cli 里执行 keys "user:*",结果为空——因为真实 key 是 user::1001,不是 user:1001。
常见表现:
- 可视化工具(如 RedisInsight、RDM)里看到空文件夹层级,点不开
-
SCAN时用MATCH user:*扫不到,但用MATCH user::*才能命中 - 缓存雪崩后手动清理失败,误以为是权限或连接问题
redis-cli 命令行下 SCAN + UNLINK 才安全
别再用 keys + xargs del。它在生产环境等于给 Redis 下达“停服指令”——单线程阻塞,大 key 一扫就卡死。
正确姿势是用 SCAN 游标式遍历 + UNLINK 异步删除:
示例:删掉所有以 user:: 开头的 key(注意双冒号):
redis-cli -h 127.0.0.1 -p 6379 --scan --pattern "user::*" | xargs -n 100 redis-cli -h 127.0.0.1 -p 6379 UNLINK
关键点:
-
--scan是 redis-cli 封装的 SCAN 迭代,比手写游标更省事 -
UNLINK比DEL安全:它把删除动作丢给后台线程,不阻塞主线程 -
-n 100控制每次传给UNLINK的 key 数量,防管道溢出或命令过长 - 如果 key 名含空格或特殊字符,加
-d "\n"确保按行分隔
Java 侧用 RedisConnection.scan 配合 pipeline 批量删
Spring Data Redis 的 redisTemplate.keys() 是个陷阱:它底层调 KEYS,禁止在生产用。
必须走 execute() + RedisConnection.scan():
redisTemplate.execute((RedisCallback<Object>) connection -> {
ScanOptions options = ScanOptions.scanOptions()
.match("user::*")
.count(500)
.build();
try (Cursor<byte[]> cursor = connection.scan(options)) {
List<byte[]> keysToDelete = new ArrayList<>();
while (cursor.hasNext()) {
keysToDelete.add(cursor.next());
if (keysToDelete.size() >= 100) {
connection.del(keysToDelete.toArray(new byte[0][]));
keysToDelete.clear();
}
}
if (!keysToDelete.isEmpty()) {
connection.del(keysToDelete.toArray(new byte[0][]));
}
}
return null;
});
注意:
-
count设为 500 是经验值,太小扫描轮次多,太大内存压力高 - 手动攒
del批量调用,比逐个del效率高;但单批别超 500 个 key,避免 pipeline 超时 - 务必用
try-with-resources关闭Cursor,否则游标泄漏
真正要禁掉的不是前缀,是默认序列化器
双冒号只是表象,根因是 Spring 默认用了 JdkSerializationRedisSerializer 或带前缀的 StringRedisSerializer。它不光加 ::,还可能把 key 序列化成二进制乱码。
解决办法不是“绕着走”,而是重置序列化逻辑:
- 显式配置
StringRedisTemplate,它默认用StringRedisSerializer,key/value 都是明文 - 若必须用
RedisTemplate,则 setKeySerializer 和 setValueSerializer 全部设为StringRedisSerializer - 在
RedisCacheConfiguration中关掉默认前缀:.computePrefixWith(key -> key)
没改序列化器之前,任何删除脚本都像在雾里打靶——你猜的 key 名,和 Redis 里存的,根本不是一回事。

















