RedisTemplate 的 delete(Collection) 方法确实能执行批量删除操作,但它并非万能工具——它只会删除你明确传入的 key 列表,不支持通配符匹配,不会触发 FLUSHALL,更不会自动帮你查询 key。如果使用场景不当或序列化配置有误,就可能遇到删不掉、删得慢、甚至内存溢出(OOM)等问题,这些都是实际开发中常见的坑。

RedisTemplate.keys(pattern) 返回空?先检查序列化器配置
一个常见现象:调用 redisTemplate.keys("user:*") 总是返回空集合,但明明 Redis 中已经存在 user:1、user:2 这些 key。问题到底出在哪里?
根本原因在于:默认的 RedisTemplate 的 keySerializer 是 JdkSerializationRedisSerializer,它会使用 Java 序列化给 key 添加前缀(例如 \xac\xed\x00\x05),导致服务端收到的命令匹配的是经过序列化后的“乱码” key,而不是你期望的纯字符串。于是 KEYS 命令自然什么都查不到。
解决办法其实很简单:显式地将 keySerializer 设置为 StringRedisSerializer。尤其当你使用字符串作为 key 时,这一步必不可少。示例配置如下:
@Bean public RedisTemplateredisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); // 其他序列化器按需设置... return template; }
如果不修改这个配置,keys("user:*") 永远找不到你存入的字符串 key——这个细节值得反复强调。
批量删除带前缀 key 的正确流程:keys + delete 分两步完成
Spring Data Redis 并没有内置“删除所有匹配前缀的 key”这样的原子方法,需要手动组合 keys() 和 delete(Collection)。具体应该如何实现?
redisTemplate.keys("order:*")返回的是Set,而不是List,可以直接传递给delete()方法。- 但需要注意:
KEYS是阻塞命令,在数据量较大的实例上使用要谨慎。生产环境推荐使用SCAN配合分批处理——不过RedisTemplate并未封装SCAN,需要自己编写逻辑。 - 一种简单安全的写法示例如下:
public void deleteByPrefix(String prefix) {
Set keys = redisTemplate.keys(prefix + "*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys); // 传入 Set,内部会转为 pipeline 批量发送 DEL
}
}
不必画蛇添足地将 keys 结果先转为 List 再转 Set,那样只会增加一次无意义的遍历。同样,也不要对空集合调用 delete(),虽然不会报错,但会浪费一次 Redis 往返通信。
delete(Collection) 的实际行为与限制
这个方法名称听起来像是“批量删除”,但底层实现其实是把集合中的每个 key 封装成一个 DEL 命令,通过 pipeline 发送——它既不是单条 DEL,也不是 FLUSHDB。具体细节需要留意:
- 传入
null或空集合:静默跳过,不会抛出异常。 - 传入不存在的 key:Redis 自动忽略,不影响其他 key 的删除操作。
- 传入 10 万个 key:可能触发 Redis 的
client-output-buffer-limit限制,或者导致客户端内存飙升(所有 key 都加载到 JVM 堆中)。 - 性能临界点:实测在千级 key 以内表现稳定;超过 5k 建议分批处理(例如每 500 个 key 一批),避免单次请求过大。
特别提醒:不要尝试将 "*" 传给 delete()——它不会展开通配符,只会去删除一个名为 "*" 的 key(几乎不存在)。
StringRedisTemplate 与 RedisTemplate:删除字符串 key 该选哪个?
如果你的 key 全部是字符串(例如 "user:1001"),优先使用 StringRedisTemplate。为什么?
StringRedisTemplate默认使用StringRedisSerializer,省去了手动配置序列化器的麻烦。redisTemplate.keys()和stringRedisTemplate.keys()的行为完全一致,但前者容易因序列化器配置错误而失效。- 两者的
delete(Collection)方法签名和逻辑完全相同,只是泛型约束不同。 - 混用风险:如果写入缓存时使用
RedisTemplate(JDK 序列化),而删除时使用StringRedisTemplate(字符串序列化),那么keys()查不到相应的 key,delete()也无法删除它们。
真正的关键不在于模板类名,而在于 key 序列化方式是否统一。在删除之前,务必确认写入时使用了哪种序列化器,不要等到查不到 key 时才开始怀疑人生。
