排他制御には悲観的ロックと楽観的ロックがあります。

悲観的ロック:
    自分が操作している情報(レコード)は他人も操作する可能性がある
  という観点から施される排他制御方法です。
  具体例としては、あるレコードを操作する前に行ロックをかけてから参照・更新し、終了後にロックを解除する方法が取られるみたいです。

楽観的ロック:
    自分が操作している情報(レコード)はまず他人は操作することがない
  という観点から施される排他制御方法です。
  具体例としては、あるレコードを読み込んだときに、当該レコードの最終更新時刻を取得し、自分が更新するときにその更新時刻が変更されていた場合にロールバックする方法が取られます。

  ただ、悲観的ロックを掛けた場合、他のトランザクションがロックの解放待ちになるため、スループットが低下すると言われています。

  一般的なシステムでは楽観的ロックで十分と言われているので、楽観的ロックを掛けたいと思います。Ruby on RailsのActiveRecordでは、簡単に楽観的ロックを実現する方法があるらしいので、今回はそれを採用。


ロックを掛けたいテーブルに以下のカラムを追加します。
  カラム名: lock_version
  カラム型: integer
  初期値: 0  (← あったほうが無難だそう。)
追加するだけで、Railsが「こいつは楽観的ロックを掛けたいんだな~」っていうのを自動的に判断してくれて、勝手に排他制御してくれるみたいです。スバラシイ!!

例えばあるサイトの会員情報を管理するテーブルusersにカラムを追加する場合、以下のようなマイグレーションファイルを用意します。

====================================================
class AddLockVersionToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :lock_version, :integer,
      :null => false, :default => 0
  end

  def self.down
    remove_column :users, :lock_version
  end
end
=====================================================

んでもって、マイグレート実行。

これで、もしレコードの更新時に他のトランザクションで先に更新されていた場合、エラーとなりロールバックされるようになります。

=====================================================
def update
  @user = User.find(params[:id])
  begin
    User.transaction do
      @user.update_attributes!(params[:user])
      redirect_to(@user)
    end
  rescue ActiveRecord::StaleObjectError
    flash[:error] = "他の人によって変更されました。"
    render :action => 'edit'
  end
end
=====================================================

ここでポイントいくつか。
  1.lock_versionを定義したモデル(ここではUser)のtransactionメソッドにコードブロックを渡してあげること。
  2.ブロック中で例外が発生するように、save!とかupdate_attributes!とか「!」つきのメソッドで更新すること。
  3.発生するエラーは、"ActiveRecord::StaleObjectError"。

すると、更新するときに

  UPDATE users
  SET `lock_version` = 1, `updated_at` = '2010-07-09 XX:XX:XX'
  WHERE id = 1
  AND `lock_version` = 0
(usersの他のカラムについては省略。)

とか勝手にやってくれます。失敗するとExceptionを投げるっていうね。
とても便利ですね~。

参考URL → http://blogs.embarcadero.com/teamj/2009/01/31/369/