2013-05-08 66 views
2

我有一個帶有多個計數器緩存的數據庫模式。我不想讓計數器緩存跨越很多表,我想要一個名爲user_counters的表以及所有各種計數器緩存。我想更新從服務對象,這些緩存使用這樣的方法:Rails計數器緩存

def update_user_counter(column, user_id) 
    UserCounter.increment_counter(column, user_id) 
end 

但是,對相關用戶的UserCounter記錄很可能不會有相同的ID的用戶。我想要做的是這樣的:

def update_user_counter(column, user_id)  
    UserCounter.increment_counter(column, UserCounter.where('user_id = "#{user_id}"') 
end 

任何想法,我怎麼能做到這一點?謝謝!!

+0

出於好奇:爲什麼?在編寫所有新代碼時,這裏有一些嚴重的技術債務,那麼這個模式提供了什麼優勢? – Matchu 2013-05-08 03:34:41

+0

很好的問題......這個user_counters表大約有10個計數器緩存列,用於許多頁面瀏覽。因此,不是運行10個單獨的查詢來獲取10個緩存計數器值中的每一個,我就可以運行1個查詢。我沒有任何其他緩存策略正在運行(例如,memcached),所以這似乎是最有效的替代方法。 – 2013-05-08 03:43:09

+0

你有沒有考慮過在數據庫中使用觸發器來實現這個功能?是的,Rails認爲數據庫中不應該有任何邏輯,但有時Rails是愚蠢和短視的。 – 2013-05-08 03:59:11

回答

2

如果這些是與用戶關聯的10個屬性,是否有任何理由不簡單地使它們成爲用戶模型的一部分?如果是這樣的話,下面的代碼仍然可以工作(只是將用戶的方法改爲UserCounter的一部分)。

如果你想以你的方式實現它,首先要確保你的user_counters表在user_id上有一個索引(因爲Rails在添加索引和FK方面是愚蠢的)。

然後,你可以這樣做(在 「列」 作爲一個符號傳遞):

class UserCounter < ActiveRecord::Base 
    #other code 

    def self.update_user_counter(column, user_id) 
    counter = UserCounter.find_by_user_id(user_id) 
    counter.update_attribute(column, counter.read_attribute(column) + 1) 
    counter.save! 
    end 
end 

而在你的其他型號:

class SomeOtherModel < ActiveRecord::Base 
    #Model code 

    def update_counter(user) 
    UserCounter.update_user_counter(:this_column, user.id) 
    end 
end 

此溶液(或使用update_counter法)都需要兩個數據庫命中,一個用於查找,一個用於更新。如果你需要的速度,你可以在SQL直接寫:

query = "UPDATE user_counters SET #{column} = #{column} + 1 WHERE user_id = #{user_id};" 
ActiveRecord::Base.connection.execute(query); 

這是假定user_iduser_counters獨特。

+0

感謝您的建議 - 他們目前在用戶模型中,但該模型變得非常非常胖,並且隨着模型的一部分變得非常沉重而加載計數器。我知道我可以在增量_counter方法之前執行find操作,但我更希望能夠在運行時動態獲取計數器行ID(基於user_id) - 以便利用increment_counter執行原始SQL命令這一事實。 – 2013-05-08 16:16:40

+0

'UserCounter.where(user_id:user_id).id'將返回UserCounter行標識,如果這是您對原始SQL所需的。無論哪種方式,您仍然對數據庫進行兩次往返(一次用於查找,一次用於增量)。更新上面的答案,包括我認爲可能爲你工作的內容。 – mikeryz 2013-05-08 18:17:50

+0

感謝您的建議!我將答案標記爲正確,因爲從技術上講,這是正確的。不幸的是,這是次優的,因爲如前所述,還有兩次往返數據庫。也許我會創建我自己的increment_counter方法來完成任務。與此同時,在油炸更大的魚。 – 2013-05-08 19:03:24