← 中文资源

简体中文版本

缓存重复失败查询的负缓存

用较短 TTL 记住未找到的查询结果,避免重复昂贵调用,并区分命中、负缓存命中与未命中。

阅读英文原文

功能说明

查询不存在的数据时,如果每次都访问数据库,会增加延迟并放大缓存穿透风险。NegativeCache 同时缓存命中的值和未命中的空结果,并为每条记录设置 TTL,过期后重新查询。get 返回 hit 标记,value 为 null 表示负缓存命中,从而与真正未命中区分。

关键代码

构造时校验 TTL 为正数并允许注入时钟。get 未找到或已过期都返回 hit:false,过期记录会被删除;value 为 null 时只返回 hit:true。withNegativeCache 先查缓存,未命中时调用 loader,根据 null 结果写入负缓存或正常值。

const cached = cache.get(key);
if (cached.hit) return cached.value ?? null;
const value = await loader();
if (value === null) cache.setMiss(key);
else cache.setValue(key, value);
return value;

使用注意

负缓存会延迟新数据可见时间,TTL 应短于正常缓存。该实现只缓存 null 表示不存在,不缓存加载异常,避免把临时故障固化。键可以是任意类型,但应保持稳定。多实例之间不共享,生产环境可替换为 Redis。setValue 拒绝 null,防止语义混淆。

验证方式

断言首次查询调用 loader,第二次命中缓存不再调用。负缓存命中返回 null。TTL 到期后重新调用 loader。setValue 后 get 返回 hit 与值。ttlMs 为 0 抛 RangeError,setValue 传 null 抛 TypeError,loader 非函数抛 TypeError。