Railsでの遅延トランザクションと並行性

経験上、楽観的ロックの場合はトランザクションを始める前に対象レコードをすべて読み込んでしまい、必要な処理を施し(カラムデータの変更など)、その後で、ActiveRecord::Base.transactionでトランザクションを開始し、レコードをまとめて保存する(save!を使う)。すると、複数テーブルを同時に更新する際の原子性を確保しやすい。

あらかじめ、関連するレコードをロックしてからレコードの読み出しを行うような場合は(悲観的ロックを併用する場合は)トランザクションブロックで、sample_model = SampleModel.find(:first, :lock => true)のようにロックをかけてからレコードを読み込む。InnoDBの場合、レコード単位にロックがかかり便利。

いずれにせよ、Railsアプリケーションで複数ユーザが同時に共通のリソースにCRUDするなら、常にこういった並行性問題を考えなければならないのだが、作業量として大変な場合が多々あり、しかも並行状態を作るテストが難しい。