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

Rails底层缓存(Low Level Cache)在记录更新时的过期实现方案咨询

解决Rails底层缓存更新时自动过期的问题

你已经尝试了用after_save回调删除缓存的方法,这确实能解决问题,但还有几种更优雅、低耦合的方案可以选择,我给你详细拆解一下:

方案一:利用cache_key_with_version自动生成带版本的缓存键

Rails的cache_key_with_version会生成包含记录ID和最后更新时间戳的键(比如users/1-20220316023452830286),当记录更新(包括touch操作)时,这个键会自动变化,自然触发缓存更新。

唯一的问题是首次请求时还没有用户对象,我们可以先查询一次记录(这是首次请求无法避免的)来生成正确的缓存键,之后的请求就会直接从缓存读取:

# 控制器代码
def show
  user_id = params[:id]
  @user = Rails.cache.fetch(user_cache_key(user_id)) do
    User.find(user_id)
  end
end

private

def user_cache_key(user_id)
  # 先获取用户对象生成带版本的缓存键,处理用户不存在的情况
  user = User.find_by(id: user_id)
  user ? user.cache_key_with_version : "users/#{user_id}-not-found"
end

这种方案的优势:

  • 完全不需要维护缓存清理的回调,模型和缓存逻辑解耦
  • 旧缓存会随着时间自动过期(结合你设置的expires_in),或者被缓存系统的LRU策略自动清理
  • 天然支持记录更新后的缓存自动失效

方案二:优化现有回调,让缓存清理更健壮

如果你更倾向于用回调立即清理旧缓存,可以优化你的实现,避免硬编码缓存键带来的维护问题:

# User模型代码
class User < ApplicationRecord
  after_save :expire_user_cache

  private

  def expire_user_cache
    # 删除所有以当前用户ID开头的缓存键,兼容任何带版本或不带版本的键格式
    Rails.cache.delete_matched("users/#{self.id}*")
  end
end

这样修改后,不管你后续怎么调整缓存键的格式(比如加版本号、前缀),只要键的前缀是users/[id],都会被正确清理,比固定删除某个键更灵活。

方案三:批量操作时的优化(可选)

如果你的系统有批量更新用户的场景,上面的回调会触发大量缓存删除操作,影响性能。这时可以改用手动触发缓存清理的方式,在批量操作完成后统一清理相关缓存:

# 批量更新后清理缓存
User.where(active: true).update_all(active: false)
# 批量删除匹配的缓存键
Rails.cache.delete_matched("users/*")

当然,这种方式要根据实际业务场景使用,避免过度清理无关缓存。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 20:09:06