【问题标题】:How to store nil with Rails.cache.fetch & memcache?如何使用 Rails.cache.fetch 和 memcache 存储 nil?
【发布时间】:2015-08-03 17:01:38
【问题描述】:

我有一个现有的模型单例方法触发了我想对缓存建模的昂贵的数据库查询。为此,我在有问题的方法周围包裹了一个Rails.cache.fetch() 调用:

# app/models/specialist.rb
class Specialist < ActiveRecord::Base

  def city
    Rails.cache.fetch([self.class.name, self.id, "city"], expires_in: 23.hours) do

      # expensive legacy query:
      if responded?
        o = offices.first
        return nil if o.blank?
        return o.city
      elsif hospital_or_clinic_only?
        (hospitals.map{ |h| h.city } + clinics.map{ |c| c.cities }).flatten.reject{ |i| i == nil }.uniq.first
      elsif hospital_or_clinic_referrals_only?
        (offices.map{ |o| o.city } + hospitals.map{ |h| h.city } + clinics.map{ |c| c.cities }).flatten.reject{ |c| c.blank? }.uniq.first
      else
        nil
      end

    end
  end

end

在过去的所有记录上执行.city 需要 16 秒;有了这个Rails.cache.fetch 块,它只下降到 7 秒,因为一半的记录仍在触发数据库调用。

当我进行调查时,我发现当city 方法返回nil 时,Rails.cache 不会将结果写入内存缓存——这意味着我的一半专家记录尽管被“缓存”了,但仍会触发昂贵的数据库查找

如何在使用 memcache 时强制 Rails.cache.fetch 存储 nil 的值,以免触发另一个数据库查找再次查找 nil?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 caching null memcached


    【解决方案1】:

    一种解决方案是使用 NullObject,如下所示:

    class Specialist
      NullData = Struct.new(nil)
    
      def city
        result = Rails.cache.fetch([self.class.name, self.id, "city"], expires_in: 23.hours) do
          if responded?
            ..
          else
            NullData.new()
          end
         result.is_a?(NullData) ? nil : result 
       end
    end
    

    这样你就创建了一个可以缓存的空对象。然后,当您返回时,检查它是否是已存储的空对象,在这种情况下,您返回 nil(以确保您不会破坏依赖于您的方法返回 nil 的旧代码),否则返回缓存的内容。

    【讨论】:

    • 这听起来很有希望,但我无法让您提供的语法正常工作。在带有 Ruby 1.9.3 的 Rails 3.1 上,我得到:/app/models/specialist.rb:235:in `new': wrong number of arguments (0 for 1+) (ArgumentError) 我更新了答案以包含我正在使用的类。您能否调整您的答案,了解如何使用Struct 为具有正确语法的单例模型方法创建NullData 对象?再次感谢您的帮助!
    • @Kelseydh 忘记了该结构至少需要一个参数。现在它应该可以工作了。
    • 谢谢。在得到你的答案后,我从我的模型中删除了NullData = Struct.new(nil)。相反,我创建了一个NullData ruby​​ 类(在lib/null_data.rb 中),让我可以在任何地方调用NullData.new。另一个问题:上面显示的“遗留”查询在某些地方回馈nil 时使用return。为了让它工作,我不得不重构遗留查询,在缓存块中不使用return,因为这导致方法中的result.is_a?(NullData) ? nil : result 被跳过。
    • @Marcus - 感谢您的回答。 1 个问题 - NullData.new() 每次都会创建新对象。是否有任何解决方法,以便我们每次都可以使用单个对象进行缓存?这不是更好吗?
    猜你喜欢
    • 2019-09-29
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 2014-01-29
    • 2011-06-23
    • 2012-06-22
    相关资源
    最近更新 更多