如何使用 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
方法 returns nil
, Rails.cache 没有将结果写入 memcache -- 这意味着我的专家记录的一半仍然尽管 "cached"
仍会触发昂贵的数据库查找
如何在使用 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
这样您就可以创建一个可以缓存的空对象。然后当你 return 你检查它是否是一个已存储的空对象,在这种情况下你 return nil (以确保你不会破坏依赖于你的方法的旧代码 returning nil),否则你 return 缓存的内容。
我有一个现有的模型单例方法触发昂贵的数据库查询,我想为缓存建模。为此,我围绕有问题的方法包装了一个 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
方法 returns nil
, Rails.cache 没有将结果写入 memcache -- 这意味着我的专家记录的一半仍然尽管 "cached"
如何在使用 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
这样您就可以创建一个可以缓存的空对象。然后当你 return 你检查它是否是一个已存储的空对象,在这种情况下你 return nil (以确保你不会破坏依赖于你的方法的旧代码 returning nil),否则你 return 缓存的内容。