2013-09-23 3 views
0

을 감안할 때 사용자 및 트랜잭션 모델 : I 사용자를 업데이트하는 경쟁 조건을 가지고잠재적 경쟁 조건이 4 개

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 

첫째 :

class User < ActiveRecord::Base 
    has_many  :transactions 
end 

class Transaction < ActiveRecord::Base 
    belongs_to :user 
end 

문제는 너무 자주라는 API로 발생 단지 @data.user을 사용하여 균형을 잡으십시오. 때로는 이전에 새로운 요청이 끝났기 때문에 일부 데이터가 손실되었습니다. 대신 그 사용자에 대한 잠금을 요청하기 시작했습니다.

다음 경쟁 조건은 총 트랜잭션 수를 세는 것과 같았습니다. 이제 알 수 있듯이 inform_user에 다른 RC가 있습니다.

그래서 내가 잘못한 점은 무엇입니까?

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

그리고 또 다른 질문, 그것은 부모를 업데이트하는 동안 나는 관계 모델을 업데이트해야 할 때, 예를 들어 중첩 잠금을 사용하는 좋은 방법이다 : 그것은과 inform_user의 업데이트 균형을 다시 할 수있는 좋은 방법이 있나요?

답변

2

데이터베이스에있는 것을 기반으로 추가/제거하여 데이터베이스를 직접 업데이트해야합니다 (Rails 모델이 현재 가지고있는 것은 아닙니다). 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

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

레일 API는 복잡한 모델과 함께 작동하지 않는 간단한 트랜잭션을 사용하여 제시하기 때문에, 그것은 좋은 대신 Model.transaction의 사용자 잔액을 업데이트하는 update_counters을 사용하는 것입니다,이 조언을 주셔서 감사합니다. 또한 모델을 만들거나 업데이트 할 때 모델을 잠그는 가장 좋은 방법은 무엇입니까? – nateless

관련 문제