ロックには2つの一般的なアプローチがあります。
まず、悲観的なロックがあります。このアプローチでは、行をロックします(SELECT ... FOR UPDATE
)他の人が行を変更できないようにします。次に、UPDATE
を実行します 。変更をコミットすると、ロックが解除されます。この場合、バージョン番号/タイムスタンプ列を用意する必要はなく(少なくともロックをサポートしないため)、コードは比較的簡単です。
悲観的なロックの欠点は、ユーザーがデータを編集している可能性のあるページに座っている間、ロックを保持する必要があることです。 HTTPはステートレスプロトコルであるため、Webベースのアプリケーションを構築している場合、これは技術的に非常に困難です。最初にページをレンダリングするリクエストは、通常、接続プールから接続を取得します。SELECT
を実行します。 、ページが完成したら、接続をプールに戻します。データを更新するための後続の要求は、通常、別のデータベースセッションとの別の接続で発生するため、最初のセッションで行をロックして2番目のセッションで行を更新することはできません。悲観的に行をロックしたい場合は、ユーザーがデータの編集を完了するまで、1つのデータベース接続が特定の中間層セッションに関連付けられていることを確認するためにバックエンドで多くの作業を行う必要があります。これは一般にスケーラビリティに非常に悪影響を及ぼし、あらゆる種類のセッション管理の問題を引き起こします。たとえば、ページをリクエストし、行をロックし、ログアウトしたり変更を加えたりせずにブラウザを閉じたかどうかをどのように知ることができますか?レコードをデータベースにロックしたままにしておく期間はどれくらいですか?他のセッションが行をロックしようとするとどうなりますか?最初の人が昼食に出かけた場合、そのセッションをどのくらいの間ロックを待つようにしますか?一般に、セッションとセッション状態の管理は非現実的すぎるため、Webベースのアプリに悲観的なロックを実装することはありません。
2番目のオプションは楽観的ロックです。このアプローチでは、バージョン番号/タイムスタンプを行に追加します。データを照会するときに、このバージョン番号/タイムスタンプを選択します。次に、これをWHERE
で使用します 後で更新を行い、実際に変更された行数を確認するときの句。 1つの行だけを変更すると、その行を読んでから変更されていないことがわかります。 0行を変更すると、行が変更されたことがわかり、エラーを処理できます。
したがって、たとえば、バージョン番号とともにデータを選択します
SELECT address_line1, city, state, zip, version
FROM addressTable
WHERE address_id = `<<some key>>`
更新を行う準備ができたら、version
を使用して次のようにします。 UPDATE
で 行が変更された場合はエラーをスローします
UPDATE addressTable
SET address_line1 = `<<new address line 1>>`,
city = `<<new city>>`,
state = `<<new state>>`,
zip = `<<new zip>>`,
version = version + 1
WHERE address_id = `<<some key>>`
AND version = `<<version you read initially>>`
IF( SQL%ROWCOUNT = 0 )
THEN
-- Darn. The row must have changed since you read it. Do something to
-- alert the user. Most likely, the application will need to re-query the
-- data to see what the address has been changed to and then ask the user
-- whether they want to re-apply the changes.
RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;
その場合、アプリケーションはエラーに対して何か有用なことをします。通常、これは、データを再度クエリし、変更をユーザーに提示し、変更を適用するかどうかをユーザーに尋ねるようなことを意味します。たとえば、住所を読んで編集を開始し、昼食に行き、同僚がログインして同じ住所を読み、編集して保存した後、戻って変更を保存しようとすると、通常は理にかなっています。同僚がすでに住所を新しいものに変更したことを示す何かを見せるために、編集を続けたいのか、それとも放棄したいのか。