2012-03-15 36 views
2

我們在Rails 3.0.6上。在Rails控制器中跨請求和跨用戶保持內存價值?使用類變量?

我們維護的數字列表僅每月更改一次,但幾乎每個頁面請求都需要訪問此列表。

我們將列表存儲在數據庫中。

而不是在每個請求上敲擊數據庫並抓取列表,我們想抓取數據一次並將其存儲在內存中以便高效訪問。

如果我們在每個用戶會話中存儲列表,我們仍然需要爲每個會話點擊數據庫。

有沒有辦法只打一次數據庫,並讓這些值在所有用戶和所有會話中的內存中保留?我們需要從控制器訪問列表。我們應該在控制器中定義一個類變量嗎?

謝謝!

回答

6

我認爲Rails.cache是在這裏你的問題的答案。這是一個帶有多個後端的簡單界面,默認情況下會將緩存存儲在內存中,但是如果您已在應用中使用Memcached,Redis或類似內容,則可以將其插入到其中。

嘗試投擲類似這樣的東西在你的ApplicationController

def list_of_numbers 
    @list_of_numbers ||= Rails.cache.fetch(:list_of_numbers, :expires_in => 24.hours) do 
    # Read from database 
    end 
end 

它會嘗試從緩存中讀取,但如果它沒有找到它,會做密集的東西,它存儲下一次

+0

謝謝!我們是否將值存儲在類變量中,以便通過請求和操作來訪問它們? – Crashalot 2012-03-15 19:13:45

+0

布拉德利得出了同樣的結論,比我在答案中更快,更實際的方式:-)。不,Rails.cache替代了類變量的方法。 – 2012-03-15 19:15:37

+0

我剛更新了包含me忘記的方法,我忘記了,謝謝tharrison。跨實例的類方法很少是一個好主意,從Rails緩存中讀取幾乎是免費的,因此您可以調用該方法。這裏唯一的問題是如果你有多個服務器,數據可能在不同服務器上有所不同。在這種情況下,肯定會考慮將諸如Memcached之類的東西插入到Rails.cache的後端 – 2012-03-15 19:19:39

2

你正在尋找的模式被稱爲單例,它是一種緩存不隨時間變化的簡單方法,例如,你會在application_controller.rb中看到類似的東西 - 你的代碼始終調用方法

def current_user(user_id) 
    @current_user ||= User.find user_id 
end 

當它發生時,它會檢查實例變量@current_user,如果不是nil則返回它,否則它會執行數據庫查找並將結果賦給它返回的實例變量。

您的問題類似,但更廣泛,因爲它適用於所有實例。

一種解決方案是使用類變量,此處記錄了http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html#S3 - 上述類似的解決方案適用於此處。

這可能是一個很好的解決方案,但有一些問題。具體來說(假設這是一個Web應用程序)取決於您的配置,您可能會在不同的進程中加載​​多個Rails實例,而類變量僅適用於其特定實例。流行的Passenger模塊(用於Apache和Nginx)可以配置爲允許類變量可以被其所有實例訪問......如果您只有一臺服務器,這非常有用。

但是,當你有多個服務器時,事情會變得有點棘手。當然,你可以使用一個類變量,並接受你必須爲每個服務器創建一個命中數據庫。除了當變量...變化時,這很好用!您需要一些方法來使所有服務器上的變量無效。取決於它的重要性,這可能會造成各種非常難以追查的錯誤(我學會了艱難的方式:-)。

輸入memcached。這是一個很棒的工具,它是一個通用緩存工具。它非常輕巧,非常非常聰明。特別是,它可以在一組服務器上創建分佈式緩存 - 該值只存儲過一次(從而避免了上述同步問題),並且每個服務器都知道要查找哪個服務器以查找任何給定的緩存密鑰。它甚至可以處理服務器停機和各種其他不愉快情況。

安裝非常簡單,Rails幾乎假設您將使用它來滿足您的各種緩存需求,並且Rails gem只是簡單得像餡餅一樣。

假設還有其他機會來緩存可能不像存儲在類變量中的值那麼簡單的東西,那可能是第一個開始的地方。