사람들이 항목을 등록하는 앱이 있습니다. 각 항목에는 제한된 수의 슬롯이 있습니다. 어떻게 동시성을 처리 할 수 있습니까? Item 클래스에서 다음과 같이 시도했습니다.ActiveRecord의 동시성 On
def sign_up(signup)
ActiveRecord::Base.transaction do
return 'Sorry, that item is full.' if full?
signups << signup
sheet.save!
nil
end
end
def full?
locked_signups = signups.lock(true).all
locked_signups.size >= max_signups
end
AR을 통해 가능한 작업을 수행하려고합니까? 열을 통해 자체 잠금을 구현해야합니까? 어떤 제안이라도 환영합니다.
업데이트 : 나는 태드 먼의 대답에 따라이 작업을했습니다. 다음은 작동하는 코드입니다.
rows_updated = ActiveRecord::Base.transaction do
Item.connection.update "update items set signup_count=signup_count+1 where id=#{ActiveRecord::Base.sanitize(self.id)} and signup_count<quantity"
end
return 'Sorry, that item is full. Refresh the page to see what\'s still open.' if rows_updated < 1
어느 옵션을 사용하더라도 동일한 동시성 문제가 발생하지 않습니까? 두 번째 (세 번째, 네 번째 등) 사용자는 이전 사용자가 슬롯 (새 서명 행을 삽입 함)을 청구하고 signups_remaining에 대한 업데이트가 커밋되기 전에 signups_remaining 값을 읽습니다. –
두 가지 경우 모두 신뢰할 수 있습니다. 첫 번째 경우에는 부족한 재고가 있으면 쿼리가 실행되지 않고 두 번째 경우에는 현재 할당되지 않은 것만을 요구하기 때문입니다. 'WHERE allocation_id is NULL'은 이전 작업을 덮어 쓰지 않도록합니다. 이는 실행 또는 실행되지 않는 단일 원자 명령문이기 때문에 가능합니다. 두 개의 개별 쿼리는 동기화하기가 훨씬 더 어렵습니다. – tadman