6月2日 01:50

TypeORM 查询缓存怎么配?Redis 缓存和缓存一致性实战

数据库查询是后端应用最常见的性能瓶颈。缓存是第一道防线——能从缓存拿的数据就不查数据库。TypeORM 支持查询级缓存和 Redis 缓存,配置简单但有几个细节要注意。

TypeORM 查询缓存

开启缓存后,相同的 SQL 查询结果会被缓存,指定时间内不重复查数据库:

typescript
TypeOrmModule.forRoot({ type: 'postgres', cache: { type: 'redis', options: { host: 'localhost', port: 6379, }, duration: 30000, // 缓存 30 秒 }, }),

在查询时指定缓存:

typescript
const users = await userRepo.find({ cache: true, // 使用全局 duration(30 秒) }); // 或自定义缓存时间 const users = await userRepo.find({ cache: 60000, // 缓存 60 秒 }); // QueryBuilder 也可以 const users = await createQueryBuilder('user') .cache(true) .getMany();

缓存 key 基于 SQL 语句自动生成——相同 SQL 共享缓存,不同 SQL 各自缓存。

什么时候用缓存

适合缓存的查询

  • 配置数据(很少变)
  • 用户信息(变更频率低)
  • 热门文章列表(可以接受短暂不一致)

不适合缓存的查询

  • 实时数据(库存、余额)
  • 分页偏移大的查询(缓存命中率低)
  • 写多读少的数据(缓存频繁失效)

缓存一致性

缓存的经典问题:数据库更新了但缓存还是旧数据。TypeORM 不会自动在数据变更时清除缓存——需要手动处理。

方案一:写入后清除缓存

typescript
async function updateUser(id: number, data: Partial<User>) { await userRepo.update(id, data); // 清除与 User 相关的所有缓存 await getConnection().queryResultCache.clear(); }

queryResultCache.clear() 清除所有缓存,比较粗暴但简单。精细清除需要知道具体的缓存 key,TypeORM 没有直接提供按表清除的 API。

方案二:短过期时间 + 接受短暂不一致

typescript
const users = await userRepo.find({ cache: 5000, // 5 秒过期,最多延迟 5 秒 });

简单有效,大部分场景够用。5 秒的不一致对用户体验几乎没有影响。

方案三:手动管理缓存(Redis 直接操作)

绕过 TypeORM 的缓存机制,用 ioredis 自己管理:

typescript
import Redis from 'ioredis'; const redis = new Redis(); async function getUser(id: string) { const cached = await redis.get(`user:${id}`); if (cached) return JSON.parse(cached); const user = await userRepo.findOne(id); await redis.set(`user:${id}`, JSON.stringify(user), 'EX', 60); return user; } async function updateUser(id: string, data: Partial<User>) { await userRepo.update(id, data); await redis.del(`user:${id}`); // 精确清除 }

自己管理更灵活——可以按 key 精确清除、设置不同过期时间、做缓存预热。但需要更多代码。

缓存命中率监控

Redis 缓存命中率反映了缓存是否有效:

bash
redis-cli info stats | grep keyspace_hits redis-cli info stats | grep keyspace_misses

命中率低于 50% 说明缓存策略有问题——要么过期时间太短,要么查询太分散没有复用。

TypeORM 缓存的局限

  • 缓存粒度是 SQL 级别,不是实体级别。同一个 User 的不同查询(列表查询 vs 详情查询)有各自独立的缓存
  • 没有 Cache Aside 模式的内置支持(先查缓存再查数据库)
  • 分布式环境下需要用 Redis 共享缓存,内存缓存(默认)会导致各实例缓存不一致

如果缓存需求复杂,建议绕过 TypeORM 缓存,直接用 Redis + 自定义缓存层。

标签:TypeORM