簡體   English   中英

如何使用 Rails.cache.fetch 和 memcache 存儲 nil?

[英]How to store nil with Rails.cache.fetch & memcache?

我有一個現有的模型單例方法觸發我想要模型緩存的昂貴的數據庫查詢。 為此,我圍繞相關方法封裝了一個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——這意味着我的一半專家記錄仍然會觸發昂貴的數據庫查找,盡管被“緩存”

如何在使用 memcache 時強制Rails.cache.fetch存儲nil的值,以便不會觸發另一個數據庫查找以再次查找 nil?

一種解決方案是使用 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 的舊代碼),否則你返回緩存的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM