在NestJS中如何借助cache-manager和cache-manager-redis-store实现Redis按匹配模式批量删除键?
我之前在NestJS项目里也碰到过一模一样的问题——cache-manager的上层封装确实把Redis的一些原生方法给藏起来了,一开始找底层客户端找得我头大。不过别担心,有几种靠谱的办法能实现按模式批量删键的需求,我给你慢慢说:
方法一:获取cache-manager封装的底层Redis客户端(推荐)
不同版本的cache-manager-redis-store对底层客户端的暴露方式略有不同,你之前试的this.cache.store.client或者this.cache.stores[0].client可能因为版本问题不生效,试试下面的方式:
步骤1:正确获取Redis客户端
在新版本的cache-manager-redis-store(比如v5及以上),底层客户端需要通过getClient()方法获取,老版本可能直接是store.client属性。你可以在你的服务里这么写:
const redisStore = this.cache.store as any; const redisClient = redisStore.getClient(); // 老版本可以试试 redisStore.client
这里用as any是因为cache-manager的类型定义没有暴露这些底层方法,暂时绕过类型检查就行,后续也可以自己扩展类型定义来避免any。
步骤2:用SCAN命令遍历匹配的键(别用KEYS!)
千万不要用KEYS命令,它是阻塞式的,生产环境下如果Redis里键很多,会直接导致Redis卡顿甚至假死。一定要用SCAN命令迭代遍历匹配的键,然后批量删除:
import { Inject, Injectable } from '@nestjs/common'; import { Cache } from 'cache-manager'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; @Injectable() export class CacheService { constructor(@Inject(CACHE_MANAGER) private cache: Cache) {} async deleteKeysByPattern(pattern: string): Promise<number> { const redisStore = this.cache.store as any; const redisClient = redisStore.getClient(); let cursor = '0'; let totalDeleted = 0; do { // SCAN迭代:每次取100个匹配的键,可以根据实际情况调整COUNT参数 const [nextCursor, matchedKeys] = await redisClient.scan( cursor, 'MATCH', pattern, 'COUNT', '100', ); cursor = nextCursor; if (matchedKeys.length > 0) { // 用cache-manager的mdel批量删除 await this.cache.mdel(...matchedKeys); totalDeleted += matchedKeys.length; } } while (cursor !== '0'); // 直到cursor回到0,说明遍历完成 return totalDeleted; } }
这样调用deleteKeysByPattern('user:*')就能删除所有以user:开头的键了。
方法二:单独引入Redis客户端实例
如果上面的方法因为版本兼容问题实在搞不定,你也可以单独安装ioredis或者官方的redis包,在NestJS里配置一个独立的Redis客户端provider,和cache-manager用完全相同的连接配置,这样就能直接调用原生的SCAN和DEL命令了。
比如用ioredis的话,先安装:
npm install ioredis
然后在NestJS里配置provider:
import { Module } from '@nestjs/common'; import Redis from 'ioredis'; @Module({ providers: [ { provide: 'REDIS_CLIENT', useFactory: () => { return new Redis({ host: 'localhost', // 和cache-manager的配置一致 port: 6379, password: 'your-redis-password', }); }, }, ], exports: ['REDIS_CLIENT'], }) export class RedisModule {}
之后在服务里注入使用,实现批量删除的逻辑和方法一类似,直接用原生客户端的scan和del/batch命令就行。
方法三:更换更友好的Redis存储适配器
如果上面两种方法都觉得麻烦,也可以考虑换成cache-manager-redis-yet这个包,它是cache-manager-redis-store的替代方案,API设计更清晰,更容易获取底层客户端,而且对NestJS的兼容性也很好。
最后提醒
- 生产环境一定要用SCAN,别用KEYS!
- 如果你用了类型断言
as any,最好在项目里扩展cache-manager的类型定义,避免类型报错。
内容来源于stack exchange




