2013-09-23 74 views
0

給定用戶和交易模式:潛在的競爭條件4種

class User < ActiveRecord::Base 
    has_many  :transactions 
end 

class Transaction < ActiveRecord::Base 
    belongs_to :user 
end 

問題出現一個名爲過於頻繁的API:

def trx 
    User.transaction do 

    user  = User.where(id: @data.user.id).lock(true).first 
    trx_number = user.transactions.count + 1 

    # some work 

    user.transactions.create(...) 

    change_balance = ... 

    user.balance = user.balance.to_f + change_balance.to_f 

    inform_user = user.has_valid_informee 

    if !result && inform_user 
     inform_user.balance  = inform_user.aff_balance.to_f + @amount.to_f 
     inform_user.save! 
    end 

    user.save! 
    end 

end 

首先我有一個競爭條件與更新用戶餘額只使用@data.user,有時候新的請求會在之前完成,因此我們丟失了一些數據。相反,我開始請求鎖定該用戶。

接下來的比賽狀況是計算總交易次數,正如我現在看到的那樣,我們將有另一個RC與inform_user。

所以問題是我做錯了嗎?它是重寫與inform_user的更新平衡的好辦法:

inform_user.with_lock do 
     inform_user.balance  = inform_user.aff_balance.to_f + @amount.to_f 
    end 

而另一個問題是,當我需要更新的關係模型,同時更新一個父一個使用嵌套鎖,例如一個好辦法嗎?

回答

2

您需要根據數據庫的內容(不是您的Rails模型當前有什麼)直接通過添加/減少來更新數據庫。看看update_counters

http://api.rubyonrails.org/classes/ActiveRecord/CounterCache/ClassMethods.html#method-i-update_counters

# For the Post with id of 5, decrement the comment_count by 1, and 
# increment the action_count by 1 
Post.update_counters 5, comment_count: -1, action_count: 1 
# Executes the following SQL: 
# UPDATE posts 
# SET comment_count = COALESCE(comment_count, 0) - 1, 
#  action_count = COALESCE(action_count, 0) + 1 
# WHERE id = 5 
+0

謝謝你的這個建議,是蠻好用的update_counters用於更新用戶餘額,而不是Model.transaction,由於Rails API建議使用簡單的交易不與複雜的模型工作。當我創建或更新關聯時,鎖定模型的最佳方法是什麼? – nateless