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
相关产品推荐
相关产品推荐

