1

巨大なデータベースアプリケーションがあり、リファクタリングする必要があります(これには多くの理由があります。最大の理由はセキュリティです)。

私たちがすでに持っているもの:

  • MySQLデータベース
  • 100を超えるテーブルのJPA2(Eclipselink)クラス
  • データベースに直接アクセスするクライアントアプリケーション

そこにある必要があるもの:

  • RESTインターフェース
  • データベースを介した役割でのログイン/ログアウト

私がこれまでにしたこと:

  • SpringSecurity3.1.1を使用してSpringMVC3.2.1をセットアップします
  • カスタムの使用UserDetailsService(atmをテストするための静的データのみが含まれています)
  • テスト用にいくつかのコントローラーを作成しました(単にデータを受信/提供するだけです)

設計上の問題:

  • データベースにmaaaaany@OneToManyと@ManyToManyの関係があります

1 .:(重要)

すべての子オブジェクトを含むオブジェクトツリー全体を応答として送信する場合、データベース全体を一度に送信できる可能性があります。

したがって、たとえば「すべての記事」を要求する方法が必要です。ただし、すべての子オブジェクトを省略する必要があります。私は昨日これを試しましたが、受け取ったオブジェクトは数トンのメガバイトでした。

@PersistenceContext
private EntityManager em;


@RequestMapping(method=RequestMethod.GET)
public @ResponseBody List<Article> index() {        
    List<Article> a = em.createQuery("SELECT a FROM Article a", Article.class).getResultList(); 
    return a;
}

2 .:(重要)

クライアントが記事を受け取った場合、現時点では電話をかけるだけでarticle.getAuthor()、JPAがを実行しSELECT a FROM Author a JOIN Article ar WHERE ar.author_id = ?ます。

RESTを使用すると、にリクエストを送信でき/authors/{id}ます。ただし、この方法では、モデルにが含まれているが含まれていないため、クライアント側で古いJPAモデルを使用することはできませAuthor authorLong author_id

すべてのモデルを書き直す必要がありますか、それとももっと簡単なアプローチがありますか?

3 .:(それほど重要ではない)

認証:ステートレスにするかどうか?私はこれまでステートレス認証を使用したことがありませんが、Springはそれを何らかの形でサポートしているようです。Webでいくつかのサンプル実装を見ると、セキュリティ上の懸念があります。リクエストごとに、ユーザー名とパスワードが送信されます。これは正しい方法ではありません。

誰かがそのための良い解決策を知っているなら、教えてください。それ以外の場合は、標準のHTTPセッションを使用します。

4.:

クライアントサイドモデルを設計するための最良の方法は何ですか?

public class Book {
    int id;

    List<Author> authors; //option1
    List<Integer> authorIds; //option2
    Map<Integer, Author> idAuthorMap; //option3
}

(これは複数の著者がいる本です)。3つのオプションはすべて、長所と短所が異なります。

  1. Author対応するモデルに直接アクセスすることもできますが、 RESTを介してモデルをリクエストしBook場合、モデルは今は必要ないかもしれませんが、後で必要になります。したがって、オプション2の方が適しています。
  2. BookRESTを介してモデルを直接リクエストできます。そして、を使用してauthorIds、後で対応する作成者をフェッチします。しかし、今は単純に使用することはできませんmyBook.getAuthors()
  3. これは1と2の混合です。IDBookのみが含まれているsを要求した場合、次のAuthorようなことができますidAuthorMap.put(authorId, null)

しかし、多分私のためにすべてのものを処理するJavaライブラリがありますか?!


今のところ以上です。君たちありがとう :)


多分解決策:

問題:必要なデータのみを選択してください。これは、多かれ少なかれすべて@ManyToMany@OneToMany、、@ManyToOne関係を無視することを意味します。

解決策:@JsonIgnoreおよび/またはを使用し@JsonIgnorePropertiesます。


問題:無視されたすべての関係は、データモデルを変更せずに簡単にフェッチされるはずです。

解決策:モデルの例:

class Book {
  int bId;
  Author author; // has @ManyToOne
}

class Author {
  int aId;
  List<Book> books; // has @OneToMany
}

これで、RESTを介して本をフェッチできます。GET /books/4結果は次のようになります('を介してすべての関係を無視するため@JsonIgnore):{"bId":4}

次に、関連する作成者を受け取るための別のルートを作成する必要がありますGET /books/4/author。戻ります:{"aId":6}

後方:GET /authors/6/books-> [{"bId":4},{"bId":42}]

、、、ごと@ManyToManyにルートがありますが@OneToMany@ManyToOneそれ以上はありません。したがって、これは存在しませんGET /authors/6/books/42。クライアントはを使用する必要がありますGET /books/42

4

1 に答える 1

1

まず、JPA レイヤーが関係を処理する方法を制御する必要があります。つまり、Lazy Loading と Eager loading を使用するということです。これは、次のように注釈の「フェッチ」オプションを介して簡単にコントローラーにすることができます。

@OneToMany(fetch=FetchType.Lazy)

これがJPAに伝えていることは、この関連オブジェクトについては、一部のコードが要求したときにのみロードするということです。舞台裏では、動的な「プロキシ」オブジェクトが作成/作成されています。このプロキシにアクセスしようとすると、別の SQL を実行して必要なビットを収集するのに十分スマートです。コレクションの場合、コレクション内のアイテムを反復処理することで、基礎となるオブジェクトをバッチで取得するのに十分スマートです。ただし、注意してください: これらのプロキシへのアクセスは、すべて同じ一般的なセッション内で行う必要があります。基礎となる ORM フレームワーク (Eclipselink の仕組みがわからない...私は Hybernate ユーザーです) は、サブリクエストを適切なドメイン オブジェクトに関連付ける方法を知りません。これは、Flex BlazeDS のようなトランスポート フレームワークを使用すると、より大きな効果があります。

カスケード ポリシーを設定することもできます。これは、次のような「カスケード」オプションを介して実行できます。

@OneToMany(cascade=CascadeType.ALL)

または、次のようなリストを指定できます。

@OneToMany(cascade={CascadeType.MERGE, CascadeType.REMOVE})

データベースから何を取得するかを制御したら、ドメイン オブジェクトをどのようにマーシャリングしているかを確認する必要があります。リクエストに応じて、JSON、XML、混合でこれを送信していますか? どのフレームワークを使用していますか (Jackson、FlexJSON、XStream など)? 問題は、フェッチ タイプを Lazy に設定しても、これらのフレームワークは引き続き関連オブジェクトを追跡するため、遅延ロードするように指示したすべての作業が無効になることです。ここで、マシャリング/シリアライズ スキームに特化したものになります。何をマーシャリングし、何をマーシャリングしないかをフレームワークに伝える方法を理解する必要があります。繰り返しますが、これは使用中のフレームワークに大きく依存します。

于 2013-02-22T14:47:27.640 に答える