質問
私はデータベース テーブル (MS SQL サーバー上で正規化されたもの) を設計し、少数のユーザーが情報を追加および編集するために使用するアプリケーション用のスタンドアロン Windows フロント エンドを作成しました。後日、生産エリア全体を検索できる Web インターフェイスを追加する予定です。
2 人のユーザーが同じレコードの編集を開始した場合、最後に更新をコミットしたユーザーが「勝者」となり、重要な情報が失われる可能性があることを懸念しています。いくつかの解決策が思い浮かびますが、さらに大きな問題を引き起こすかどうかはわかりません。
- 何もせず、2 人のユーザーが同時に同じレコードを編集しないことを祈ります。 - 起こらなかったかもしれませんが、もし起こったらどうしますか?
- 編集ルーチンは、元のデータのコピーと更新を保存し、ユーザーが編集を終了したときに比較できます。異なる場合は、ユーザーを表示して更新を確認します - データのコピーを 2 つ保存する必要があります。
- 最終更新日 (DATETIME) 列を追加し、更新時に一致することを確認します。一致しない場合は、相違点を表示します。 - 関連する各テーブルに新しい列が必要です。
- ユーザーがチェックされるレコードの編集を開始したときに登録し、他のユーザーが同じレコードを編集できないようにする編集テーブルを作成します。 - ユーザーがプログラムからクラッシュした場合にデッドロックやレコードがロックされるのを防ぐために、プログラム フローを注意深く考える必要があります。
より良い解決策はありますか、それともこれらのいずれかを選択する必要がありますか?
解決
頻繁に衝突が発生しないことが予想される場合は、 楽観的な同時実行性 おそらくそれが最善の策です。
Scott Mitchell は、そのパターンの実装に関する包括的なチュートリアルを書きました。
オプティミスティック同時実行性の実装
他のヒント
古典的なアプローチは次のとおりです。
- 各テーブルに「ロックされた」ブール値フィールドを追加します。
- デフォルトではこれを false に設定します。
ユーザーが編集を開始したら、次のようにします。
- 行をロックします(行をロックできない場合はテーブル全体)。
- 編集したい行のフラグをチェックします
- フラグが true の場合
- 現時点ではその行を編集できないことをユーザーに通知します
- それ以外
- フラグを true に設定します
ロックを解除します
レコードを保存するときに、フラグを false に戻します。
SELECT FOR UPDATE と同等のコマンドは、微視的な時間だけロックを保持する場合に適していますが、巨視的な量では (例:ユーザーがデータをロードしていて「保存」を押していない場合は、上記のようにオプティミスティック同時実行を使用する必要があります。(これはいつも名前が間違っていると思います。通常、他の選択肢として考えられるのはこれだけである「最後のライターが勝つ」よりも悲観的です。)
@マーク・ハリソン:SQL Server はその構文をサポートしていません (SELECT ... FOR UPDATE
).
SQL Server に相当するものは、 SELECT
ステートメントのヒント UPDLOCK
.
見る SQL Server オンライン書籍 詳細については。
-first create filed(update time)on esture ready record -任意のユーザーの選択レコードの保存時間を保存する場合、選択時間と更新時間を比較しますif(update time)>(Select time)記録
もう 1 つのオプションは、変更しているレコード内の値が開始時と同じであるかどうかをテストすることです。
SELECT
customer_nm,
customer_nm AS customer_nm_orig
FROM demo_customer
WHERE customer_id = @p_customer_id
(customer_nm フィールドを表示し、ユーザーがそれを変更します)
UPDATE demo_customer
SET customer_nm = @p_customer_name_new
WHERE customer_id = @p_customer_id
AND customer_name = @p_customer_nm_old
IF @@ROWCOUNT = 0
RAISERROR( 'Update failed: Data changed' );
テーブルに新しい列を追加する必要はありません (テーブルを最新の状態に保つ必要があります) が、より詳細な SQL ステートメントを作成して渡す必要があります。 新しい そして 古い フィールドをストアド プロシージャに追加します。
また、レコードをロックしないという利点もあります。なぜなら、レコードがロックされるべきではないときにロックされたままになってしまうことは誰もが知っているからです。
データベースがこれを実行します。「選択してください...」を見てください。for update」は、この種のもの専用に設計されています。これにより、選択した行に書き込みロックが設定され、コミットまたはロールバックできるようになります。
私の場合、列 lastupdate (timetamp データ型) を使用するのが最善の方法です。選択と更新をこの値を比較するだけで、このソリューションの別の進歩は、この列を使用してデータが変更される時間を追跡できることです。isLockのようなカラムを作って更新を確認するだけではダメだと思います。