You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apollo DataSource类中Redis缓存正确用法及现有代码无返回问题排查

代码存在的问题及修复方案

你这段代码的核心错误点如下:

  • 缺少异常捕获逻辑:整个async方法没有做错误捕获,无论是缓存读写抛出异常、数据库连接/查询报错,都会直接导致方法抛出未处理的拒绝,上层如果没有做catch处理就会直接中断,无法拿到返回值。
  • 空结果缓存穿透问题:如果数据库中没有对应id的订单,Order.findOne会返回null,此时如果传入了ttlInSeconds,你会直接把JSON.stringify(null)也就是字符串"null"写入缓存。后续相同id的请求会直接命中缓存返回null,即使后续数据库中新增了对应id的订单,在缓存过期前都会一直返回空结果。
  • 参数兼容性问题:方法第二个参数采用对象解构赋值{ttlInSeconds}={},如果调用时第二个参数传入了非对象类型(比如直接传数字order(123, 3600)),会直接抛出TypeError,导致方法执行中断。
  • 缓存生效逻辑问题:如果没有传入ttlInSeconds,所有查询结果都不会写入缓存,相当于缓存完全不生效,每次请求都会查数据库,如果你预期缓存默认生效,这也是逻辑偏差点。

修复后代码示例

async order(id, options = {}) {
  // 前置校验id合法性
  if (!id) {
    throw new Error('订单id不能为空')
  }
  // 兼容直接传ttl数字、对象传参两种调用方式
  const ttlInSeconds = typeof options === 'number' ? options : options.ttlInSeconds

  try {
    const cacheKey = this.cacheKey(id)
    const cachedOrder = await this.cache.get(cacheKey)

    if (cachedOrder) {
      const parsedOrder = JSON.parse(cachedOrder)
      return parsedOrder
    }

    const order = await this.models.Order.findOne({
      where: { id }
    })

    if (ttlInSeconds) {
      // 空值设置更短的缓存时间防穿透,避免长时间缓存无效结果
      const cacheTtl = order ? ttlInSeconds : 30
      await this.cache.set(cacheKey, JSON.stringify(order), { ttl: cacheTtl })
    }

    return order
  } catch (err) {
    // 缓存异常时降级直接查数据库,避免缓存服务不可用导致整个业务中断
    console.error('订单查询异常:', err)
    return await this.models.Order.findOne({
      where: { id }
    }).catch(dbErr => {
      console.error('数据库查询失败:', dbErr)
      throw new Error('订单查询失败')
    })
  }
}

内容的提问来源于stack exchange,提问作者Ekaterina Janssen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 06:27:00