楽観的ロックを行うには、前回表示してから行が変更されたかどうかを確認するための手段を定義する必要があります。たとえば、別の識別子を追加するだけです:
alter table regions_indexes add version_id integer default 1 not null;
これで、アプリケーションはいくつかの行を読み取り、データをユーザーに表示し、ボタンがクリックされるまで待機します。 version_id
の値を覚えておく必要があります 取得しました。
ボタンをクリックした後、必要なすべての計算を実行します。行を更新する準備ができたら、行をロックして、version_id
かどうかを確認します。 変更されていません。そうでない場合は、version_id
をインクリメントします コミットします。運が悪ければ、誰かが追い越したので、操作を繰り返すようにユーザーに指示する必要があります。
次のようになります(擬似コード):
-- remember version_id
select *
from regions_indexes
where id = ... and resource_type = ...;
-- wait for user click
-- you can wait for a long time, because no lock is yet acquired
...
update regions_indexes
set current_resource = current_resource - ..., version_id = version_id + 1
where id = ... and resource_type = ...
returning version_id;
if new_version_id = old_version_id + 1 then
-- success, commit
else
-- fail, rollback
end if;
ただし、同時実行性が高い状況では、楽観的ロックはうまく機能しません。競合がまれではない場合は、トランザクションを頻繁に再開する必要があります。