ユーザーが編集中のクラウドDBの行をロックする必要がありますか


12

データをクラウドに保持するデスクトップアプリケーションを作成しています。私が懸念していることの1つは、アプリケーション内のアイテムの編集を開始し、しばらくそれを残すとデータが古くなることです。これは、2人が同じアイテムを同時に編集しようとした場合にも発生します。編集を終えてデータを保存したい場合、データベースに現在存在するものを上書きするか、最後の変更後に編集を開始したことを確認し、変更を強制的に破棄するか、リスクを与えるオプションを与える必要があります他の人の変更を上書きする。

フィールドis_lockedlock_timestampDBテーブルに追加することを考えました。ユーザーがアイテムの編集を開始すると、行がis_lockedtrueに変更され、ロックタイムスタンプが現在の時刻に設定されます。その場合、ロックが保持される時間(5分など)があります。他の誰かがアイテムを編集しようとすると、アイテムがロックされ、ロックが自動的に期限切れになるというメッセージを受け取ります。ユーザーがロックの編集中に立ち去ると、比較的短時間でロックが自動的に期限切れになり、ロックが期限切れになったことがユーザーに警告され、データの更新後に強制的に編集が再開されます。

これは古いデータの上書きを防ぐ良い方法でしょうか?それは過剰です(アプリケーションが1つのアカウントで同時に数人以上のユーザーによって使用されるとは考えていません)。

(私が抱えているもう1つの懸念は、2人が同じアイテムのロックを取得することですが、それは私が快適な競合状態だと思います。)


1
「もう1つの懸念は、2人が同じアイテムのロックを取得することですが、それは私が快適な競合状態であると考えています」-ロックの取得に関するデータベーストランザクションを使用すると、このような競合状態を防ぐことができます。
ジュール

ほとんどのデータベースエンジン(少なくともリレーショナルの種類)には、このサポートが組み込まれています。RDBMSの世界では非常に一般的な概念であり、楽観的または悲観的ロックが必要であると言うのであれば、「おもちゃ」データベースでも十分に処理できます。とにかく、どうしても自分でビルドする必要があるとは思いません。dbエンジンのオプションをチェックして、その操作方法を確認してください。
-jleach

アプリケーションがデスクトップアプリケーション(ファットクライアント)であるという事実は、それほど違いはありません。高可用性のマルチインスタンスサーバーアプリケーションと同じ方法で設計できます。
ホサムアリー

回答:


19

ここで役立つのは、用語です。ここで説明していることは、「悲観的ロック」と呼ばれます。このアプローチの主な代替手段は「楽観的ロック」です。悲観的ロックでは、各アクターはレコードを更新する前にロックし、更新が完了したらロックを解除する必要があります。楽観的ロックでは、他の誰もレコードを更新していないと想定して試行します。レコードが他のアクターによって変更された場合、更新は失敗します。

一般に、2人のアクターが同じものを同時に更新する可能性が低い場合は、楽観的ロックが適しています。悲観的は通常、その可能性が高い場合、または開始前に更新が成功することを知る必要がある場合に使用されます。私の経験では、悲観的ロックに固有の多くの問題があるため、ほとんどの場合、楽観的ロックが望ましいです。最大の問題の1つが質問で触れられています。ユーザーは編集のためにレコードをロックしてから、昼食に出かけることができます。軽減策はそれを助けますが、ユーザーエクスペリエンスは楽観的なアプローチに勝るものはなく、はるかに悪化する可能性があります。たとえば、あるユーザーがレコードを開き、更新を開始すると、上司がデスクに現れます。別のユーザーがレコードを編集しようとしました。それはロックされています。2人目のユーザーは試行を続け、5分後に、ロックが期限切れになり、2番目のユーザーがレコードを更新します。最初のユーザーは画面に戻り、保存しようとし、ロックを失ったと伝えられます。楽観的ロックを使用する以外はすべて同じである同じシナリオでは、最初のユーザーのエクスペリエンスはほぼ同じですが、2番目のユーザーは5分間待機しません。

ロック値に楽観的ロックを実装することで、レイアウトのスキームが大幅に改善されますが、私の予想では、楽観的ロックはおそらくすべてのものでOKであり、is_lockedフィールドを削除できます。

使用している「クラウドDB」を提供しません。おそらく、その機能を調べて、独自のソリューションを実装する前に、この機能が組み込まれているかどうかを確認する必要があります。

基本的なレシピは次のとおりです。is_lockedフィールドの代わりに、バージョン番号フィールドがあります。レコードを取得すると、レコードの現在のバージョンを取得します。更新する場合、取得したものと一致するバージョンフィールドを条件に更新を行い、成功するとそれをインクリメントします。バージョンが一致しない場合、更新は効果がなく、失敗として報告します。


これは非常に役立つ答えです。「衝突」の可能性がわずかにあるときに悲観的ロックが推奨されない理由を説明できますか。編集を開始するためにデータベースにアクセスする必要があるだけなのか、それとも余分な複雑さやその他の理由が原因ですか?ありがとう!
-yitzih

3
いくつかの提案読書@yitzih:ファウラーら、エンタープライズアプリケーションアーキテクチャのパターン。この質問に関する章全体があり、すべてのオプションとそれらを選択する理由について十分に議論されています。
ジュール

2
@ジミー-あなたの答えは結構です。場合によっては、エラーを報告するだけでは十分ではありません。ユーザーがレコードの更新に数分かかる場合を考えてください。その場合、失敗だけでは十分ではないかもしれません。ユーザーに、実行中の変更を他のユーザーがコミットした変更とマージする機会をユーザーに与えることができます。オプティミスティックロックで、要件に応じて競合の解決必要になる場合があると述べたはずです。
ジョンレイナー

3
悲観的ロックは、クライアントに説明するのがはるかに簡単であることを言及する価値があります。現在別のレコードによって編集されているためにクライアントがレコードにアクセスできないというメッセージを書いた場合、クライアントはうまく理解し、一般的にそれを受け入れます。代わりに7/10の別のユーザーによって既に保存されているため、保存を保存した後にクライアントに通知できない場合、クライアントはイライラし、この奇妙なプログラムの動作の説明を期待します。
ニール

2
@Neilそれは真実であり、楽観的がより適切な場合に悲観的ロックが使用される理由はよくあると思います。多くの場合、ワークフローにより、衝突が発生する可能性は非常に低くなります。
ジミージェームズ

0

@JimmyJamesの回答から、質問がユーザーエクスペリエンスに関するものであることがわかります。

それはすべてコンテキストに依存します。レコードを更新するにはどれくらいの時間と労力がかかりますか?複数のユーザーが同じドキュメントを更新する頻度はどれくらいですか?

たとえば、ユーザーが通常レコードを更新するのに数秒かかり、競合がほとんどない場合は、おそらく楽観的ロックを使用する方法です。最悪の場合、ユーザーはドキュメントを更新するために、さらに数秒、場合によっては最大1分を費やす必要があります。

文書が非常に論争的であるが、よく構成されている場合は、30秒単位で個々のフィールドをロックし、タイマーまたは控えめな通知を表示してロックを延長できるようにすることができます。

ただし、ユーザーがかなりの時間または労力を費やす場合は、他のアプローチを検討する必要があります。あなたの記録はうまく構成されていますか?サーバー上のバージョンと保存しようとしているバージョンの比較(差分)をユーザーに表示できますか?違いを強調できますか?変更をマージさせることできますか?ソース管理ツールで得たい経験を考えてください。あなたは本当にすべてのコードを再び書くことを強制されたくありません!

追加のインスピレーションについては、Googleドキュメントをご覧ください。おそらく、新しいバージョンが保存されたという通知をユーザーに表示できます。たぶん、あなたは彼らがどれほど多くの人々がレコードを開いているかを示して、彼らがより議論の少ない時間に戻ってくることを選ぶことができるかもしれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.