0

人々がアイテムにサインアップするアプリがあります。各アイテムには限られた数のスロットがあります。同時実行を処理するにはどうすればよいですか? 私は Item クラスでこのように試しました:

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
4

1 に答える 1

1

この種の問題に対する信頼できる 2 つのアプローチを考えることができます。

カウンターコラム

「残りの在庫」列を作成し、アトミックに更新します。

UPDATE sheet SET signups_remaining=signups_remaining-:count WHERE id=:id AND signups_remaining>=:count

:countそれに応じてとの:id値にバインドする必要があります。このクエリが実行される場合、十分な数のサインアップが残っていることを意味します。

予約済みサインアップ

事前にサインアップ レコードを作成し、割り当てます。

UPDATE signups SET allocation_id=:allocation_id WHERE allocation_id IS NULL LIMIT :count

これにより、0 個以上のサインアップ レコードが更新されるため、トランザクションをコミットする前に、正しいカウントを予約したことを確認する必要があります。

于 2012-10-12T17:00:45.170 に答える