1

私は、概念実証からパイロット プロジェクトに値する何かに移行中のプロジェクトに取り組んでいます。この開発フェーズの重要な改善点の 1 つは、メモリに保持され、定期的にファイルにダンプされるハッシュ テーブルを使用する現在の「持続性」メカニズムから、より従来型のデータベース バックエンドに移行することです。

アプリケーション自体は、ReSTful の原則を念頭に置いて設計されています。Jersey を使用してリソースへのアクセスを提供し、jQuery を使用してこれらのリソースをユーザーに提示し、基本的な対話 (作成、更新、削除) を有効にします。かなり簡単です。

リレーショナル データベースでサーバー側の状態を永続化するために、過去に JPA と Hibernate を使用して成功したことがあるので、この場合は当然の選択に思えました。モデル エンティティにいくつかのマイナーな変更を加えることで、基本的な読み取り、作成、および削除操作を適切な時間内に実行できるようになりました。ただし、更新操作はより困難であることが判明しました。

アプリケーションのクライアント側部分は、ユーザーがリソースを変更してから数秒後に変更をサーバーに自動的に送信します。さらに、ユーザーがホームページに戻る直前にリソースの最新バージョンをサーバーに送信するために押すことができる「保存して閉じる」ボタンがあります。

私の最初の問題は、管理対象エンティティをデータベースから、クライアントからの管理対象外オブジェクトで更新する方法でした。クライアントに送信されるデータは意図的にデータベース キーを省略しているため、管理されていないオブジェクトの要素を Hibernate オブジェクトに明示的に「マージ」することになるため、これは少し面倒でした。これは私の質問ではありませんが、これを行うエレガントな方法を知っている人がいれば、ぜひ聞いてみたいと思います。

私の 2 番目の問題、およびこの記事の目的は、前述の自動保存操作が行われているのとほぼ同時に「保存して閉じる」ボタンを押したときに発生します。多くの場合、楽観的ロック例外が発生します。これは、最初の更新操作がまだ処理されている間に、2 番目の更新操作が別のスレッドで処理されているためです。

リソースには、更新が処理されるたびに設定される「更新された」タイムスタンプがあるため、データベースへの更新は、何も変更されていなくても毎回保証されます。これ自体はおそらく問題ですが、修正した後でも、自動保存の進行中にユーザーが変更を加えてサーバーに送信できる「機会の窓」がまだあり、同じ問題を引き起こします.

この問題に対処するために私が考えることができる最も簡単なアプローチは、クライアント側の Javascript の一部を作り直して、そのクライアントからの未解決の「更新」操作が常に 1 つだけになるようにすることです。(別のクライアントがたまたま同じリソースを同時に更新した場合、楽観的ロック例外はまったく問題ないことに注意してください。) ただし、クライアントにこの制限を強制することは、ReST の精神から逸脱する可能性があることを懸念しています。ReSTfulアプリケーションの任意の時点で、特定のクライアントが特定のリソースに対する未処理の「更新」(PUT)リクエストを1つしか持たないと期待するのは合理的ですか?

これはかなり一般的なシナリオのように思えますが、それを処理する最善の方法について決定的な答えを見つけることができませんでした. 私が検討して破棄したその他のアイデアには、同じクライアントからのリクエストを (おそらく HTTP セッションに基づいて) 何らかの方法でシリアル化し、順番に処理されるようにすること、JPA/Hibernate ワーカー スレッドの更新の「キュー」を実装すること、および新しい "単一のレコードを更新するのではなく、最新のものを追跡しながら、リソースのバージョン"。

何かご意見は?クライアントでの「一度に 1 つの未処理の更新」という制限は合理的に見えますか、それともより良いアプローチがありますか?

4

2 に答える 2

0

私の最初の問題は、管理対象エンティティをデータベースから、クライアントからの管理対象外オブジェクトで更新する方法でした。クライアントに送信されるデータは意図的にデータベース キーを省略しているため、管理されていないオブジェクトの要素を Hibernate オブジェクトに明示的に「マージ」することになるため、これは少し面倒でした。これは私の質問ではありませんが、これを行うエレガントな方法を知っている人がいれば、ぜひ聞いてみたいと思います。

クライアントが送信するリソースに id を含めるか、PUT (例: PUT /object/{objectId}) を使用する必要があります。次に、マージする必要はありませんが、「置き換える」だけです。私は常に戻ってきて、完全なリソースを期待することを好みます。厄介なマージを回避します。

私の 2 番目の問題、およびこの記事の目的は、前述の自動保存操作が行われているのとほぼ同時に「保存して閉じる」ボタンを押したときに発生します。多くの場合、楽観的ロック例外が発生します。これは、最初の更新操作がまだ処理されている間に、2 番目の更新操作が別のスレッドで処理されているためです。

あなたが言及したように、JavaScript によってクライアント側でこれを行うことができます。「dirty」フラグを導入すると、フラグ「dirty」が設定されている場合にのみ、自動保存または保存-閉じるボタンの両方がサーバーにリクエストを送信します。ユーザーが何かを変更すると、「dirty」フラグがトグルされます。サーバーにリクエストをシリアル化させないでください。複雑になります。

[...] ただし、この制限をクライアントに強制することは、ReST の精神から逸脱する可能性があることを懸念しています。ReSTfulアプリケーションの任意の時点で、特定のクライアントが特定のリソースに対する未処理の「更新」(PUT)リクエストを1つしか持たないと期待するのは合理的ですか?

REST の精神の一部は、物事を分離することであり、クライアントは CRUD 操作をいつ実行するかを適切に決定できます。

ところで:REST APIと非常にうまく連携する優れたフロントエンドJavaスクリプトフレームワークがあります:extJS。内部アプリケーションではうまく機能しました (extJS スタイルのルック アンド フィールのため、私は extJS で公開 Web サイトを作成しませんでした)。

于 2010-08-17T18:04:38.267 に答える
0

クライアントが同じ URI に対して同時に PUT 操作を実行するという同じ問題に遭遇しました。クライアントがそうするのは意味がありませんが、それが禁止されている、またはある程度 RESTful であると述べているハード ドキュメントは見つからないと思います。実際、サーバーはそれらをシリアル化し、それが発生したときに楽観的同時実行性について文句を言う以外に何もできません。正常に動作するクライアントは、GET や HEAD などの安全な操作であっても、各リソースのすべての操作を同期することでこれらを回避することが賢明です。これにより、キャッシュが古いデータで汚染されることはありません。

于 2010-08-17T19:02:41.427 に答える