web-dev-qa-db-ja.com

Spring DataのMongoTemplateとMongoRepositoryの違いは何ですか?

Spring-dataとmongodbを使用して複雑なクエリを実行できるアプリケーションを作成する必要があります。私はMongoRepositoryを使用することから始めましたが、例を見つけるため、または実際に構文を理解するために複雑なクエリに苦労しました。

私はこのようなクエリについて話している:

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    List<User> findByEmailOrLastName(String email, String lastName);
}

または、構文が正しくないため試行錯誤して試したJSONベースのクエリの使用。 mongodbのドキュメントを読んだ後でも(間違った構文による動作しない例)。

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    @Query("'$or':[{'firstName':{'$regex':?0,'$options':'i'}},{'lastName':{'$regex':?0,'$options':'i'}}]")
    List<User> findByEmailOrFirstnameOrLastnameLike(String searchText);
} 

すべてのドキュメントを読んだ後、mongoTemplateMongoRepositoryよりもはるかに優れたドキュメントになっているようです。私は次のドキュメントを参照しています:

http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/

より便利で強力なものを教えてください。 mongoTemplateまたはMongoRepository?両方とも成熟しているか、または一方が他方より多くの機能を欠いていますか?

77

「便利」と「強力な」は、ある程度矛盾する目標です。リポジトリはテンプレートよりもはるかに便利ですが、後者はもちろん実行するものをよりきめ細かく制御できます。

リポジトリプログラミングモデルは複数のSpring Dataモジュールで利用できるため、Spring Data MongoDBの一般セクションで詳細なドキュメントを見つけることができます reference docs

TL; DR

通常、次のアプローチをお勧めします。

  1. リポジトリ抽象から始めて、クエリ派生メカニズムまたは手動で定義されたクエリを使用して単純なクエリを宣言します。
  2. より複雑なクエリの場合は、手動で実装されたメソッドをリポジトリに追加します(ここで説明します)。実装にはMongoTemplateを使用します。

詳細

あなたの例では、これは次のようになります。

  1. カスタムコードのインターフェイスを定義します。

    interface CustomUserRepository {
    
      List<User> yourCustomMethod();
    }
    
  2. このクラスの実装を追加し、命名規則に従ってクラスを見つけられるようにします。

    class UserRepositoryImpl implements CustomUserRepository {
    
      private final MongoOperations operations;
    
      @Autowired
      public UserRepositoryImpl(MongoOperations operations) {
    
        Assert.notNull(operations, "MongoOperations must not be null!");
        this.operations = operations;
      }
    
      public List<User> yourCustomMethod() {
        // custom implementation here
      }
    }
    
  3. ベースリポジトリインターフェースでカスタムインターフェースを拡張し、インフラストラクチャがカスタム実装を自動的に使用するようにします。

    interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {
    
    }
    

このようにして、基本的に選択肢を得ることができます。宣言が簡単なものはすべてUserRepositoryに、手動で実装する方がよいものはすべてCustomUserRepositoryになります。カスタマイズオプションは here で文書化されています。

118
Oliver Drotbohm

この答えは少し遅れることがありますが、リポジトリ全体のルートを避けることをお勧めします。実用的な価値のある実装されたメソッドはほとんどありません。それを機能させるために、Java構成のナンセンスにぶつかります。これは、ドキュメンテーションの助けがなくても何日も何週間も費やすことができます。

代わりに、MongoTemplateルートを使用して、独自のデータアクセスレイヤーを作成し、Springプログラマが直面する構成の悪夢から解放します。 MongoTemplateは、柔軟性が非常に高いため、独自のクラスと相互作用を快適に設計できるエンジニアにとって本当に救い主です。構造は次のようになります。

  1. アプリケーションレベルで実行されるMongoClientFactoryクラスを作成し、MongoClientオブジェクトを提供します。これをシングルトンとして実装するか、Enumシングルトンを使用して実装できます(これはスレッドセーフです)
  2. 各ドメインオブジェクトのデータアクセスオブジェクトを継承できるデータアクセスベースクラスを作成します。基本クラスは、MongoTemplateオブジェクトを作成するためのメソッドを実装できます。このオブジェクトは、特定のメソッドを使用して、すべてのDBアクセスに使用できます
  3. 各ドメインオブジェクトの各データアクセスクラスは、基本的なメソッドを実装するか、基本クラスに実装できます。
  4. コントローラーメソッドは、必要に応じてデータアクセスクラスのメソッドを呼び出すことができます。
19
rameshpa

FWIW、マルチスレッド環境での更新に関して:

  • MongoTemplate は、すぐに使用できるupdateFirstupdateMultifindAndModifyupsert...メソッドを提供し、1回の操作でドキュメントを変更できるようにします。これらのメソッドで使用されるUpdateオブジェクトを使用すると、関連するフィールドのみをターゲットにすることもできます。
  • MongoRepository は、すべてのフィールドを含むPOJOで動作する基本的なfindinsertsavedelete操作のみを提供します。これにより、ドキュメントをいくつかの手順で更新する(find更新するドキュメント、返されたPOJOから関連フィールドを変更し、save it)、または@Queryを使用して手動で更新クエリを定義します。

マルチスレッド環境では、例えば複数のJavaエンドポイントを持つRESTバックエンドでは、2つの同時更新が互いの変更を上書きする可能性を減らすために、単一メソッドの更新を行う方法です。

例:次のようなドキュメントを指定します:{ _id: "ID1", field1: "a string", field2: 10.0 }と2つの異なるスレッドが同時にそれを更新しています...

MongoTemplateを使用すると、次のようになります。

THREAD_001                                                      THREAD_002
|                                                               |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
|                                                               |
|                                                               |

ドキュメントの最終状態は常に{ _id: "ID1", field1: "another string", field2: 15.0 }です。これは、各スレッドがDBに一度だけアクセスするためですand指定されたフィールドのみが変更されます。

MongoRepositoryを使用した同じケースシナリオは次のようになります。

THREAD_001                                                      THREAD_002
|                                                               |
|pojo = findById("ID1")                                         |pojo = findById("ID1")
|pojo.setField1("another string") /* field2 still 10.0 */       |pojo.setField2(pojo.getField2()+5) /* field1 still "a string" */
|save(pojo)                                                     |save(pojo)
|                                                               |
|                                                               |

最後のドキュメントは、どのsave操作が最初にDBにヒットするかに応じて、{ _id: "ID1", field1: "another string", field2: 10.0 }または{ _id: "ID1", field1: "a string", field2: 15.0 }のいずれかになります。

非常に精巧なPOJOモデルを持っているか、何らかの理由でMongoTemplateのカスタムクエリ機能が必要でない限り、MongoRepositoryの方が優れたオプションです

9
walen