web-dev-qa-db-fra.com

Quelle est la différence entre MongoTemplate et MongoRepository de Spring Data?

J'ai besoin d'écrire une application avec laquelle je peux faire des requêtes complexes en utilisant spring-data et mongodb. J'ai commencé par utiliser MongoRepository, mais je me suis débattu avec des requêtes complexes pour trouver des exemples ou pour comprendre la syntaxe.

Je parle de requêtes comme celle-ci:

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

ou l'utilisation de requêtes basées sur JSON que j'ai essayées par essais et erreurs car je ne comprends pas bien la syntaxe. Même après avoir lu la documentation de mongodb (exemple non fonctionnel en raison d’une syntaxe incorrecte).

@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);
} 

Après avoir lu toute la documentation, il semble que mongoTemplate soit beaucoup mieux documenté que MongoRepository. Je fais référence à la documentation suivante:

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

Pouvez-vous me dire ce qui est plus pratique et puissant à utiliser? mongoTemplate ou MongoRepository? Est-ce que les deux ont la même maturité ou est-ce que l'un d'eux manque de plus de fonctionnalités que l'autre?

77

"Pratique" et "puissant à utiliser" sont en quelque sorte des objectifs contradictoires. Les référentiels sont de loin plus pratiques que les modèles, mais ces derniers vous donnent bien sûr un contrôle plus fin sur ce qu’il faut exécuter.

Le modèle de programmation du référentiel étant disponible pour plusieurs modules Spring Data, vous en trouverez une documentation plus détaillée dans la section générale de Spring Data MongoDB documentation de référence .

TL; DR

Nous recommandons généralement l'approche suivante:

  1. Commencez par le résumé du référentiel et déclarez simplement les requêtes simples à l'aide du mécanisme de dérivation de requête ou de requêtes définies manuellement.
  2. Pour des requêtes plus complexes, ajoutez des méthodes implémentées manuellement au référentiel (comme documenté ici). Pour l'implémentation, utilisez MongoTemplate.

Détails

Pour votre exemple, cela ressemblerait à quelque chose comme ceci:

  1. Définissez une interface pour votre code personnalisé:

    interface CustomUserRepository {
    
      List<User> yourCustomMethod();
    }
    
  2. Ajoutez une implémentation pour cette classe et suivez la convention de dénomination pour vous assurer que nous pouvons trouver la classe.

    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. Laissez maintenant votre interface de référentiel de base étendre celle personnalisée et l'infrastructure utilisera automatiquement votre implémentation personnalisée:

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

Ainsi, vous aurez essentiellement le choix: tout ce qui est facile à déclarer va dans UserRepository, tout ce qui est mieux implémenté manuellement va dans CustomUserRepository. Les options de personnalisation sont documentées ici .

118
Oliver Drotbohm

Cette réponse est peut-être un peu retardée, mais je recommanderais d'éviter toute la route du référentiel. Vous obtenez très peu de méthodes implémentées de grande valeur pratique. Pour que cela fonctionne, vous rencontrez le non-sens de la configuration de Java) sur lequel vous pouvez passer des jours et des semaines sans beaucoup d'aide dans la documentation.

Au lieu de cela, utilisez la route MongoTemplate et créez votre propre couche d'accès aux données, ce qui vous libère des cauchemars de la configuration rencontrés par les programmeurs Spring. MongoTemplate est vraiment le sauveur des ingénieurs qui sont à l'aise pour concevoir leurs propres classes et interactions, car ils disposent de beaucoup de flexibilité. La structure peut être quelque chose comme ceci:

  1. Créez une classe MongoClientFactory à exécuter au niveau de l'application et créez un objet MongoClient. Vous pouvez l'implémenter en tant que Singleton ou en utilisant un Enum Singleton (c'est thread-safe)
  2. Créez une classe de base d'accès aux données à partir de laquelle vous pouvez hériter d'un objet d'accès aux données pour chaque objet de domaine. La classe de base peut implémenter une méthode pour créer un objet MongoTemplate que vous pouvez utiliser avec des méthodes spécifiques à chaque classe pour tous les accès à la base de données.
  3. Chaque classe d'accès aux données pour chaque objet de domaine peut implémenter les méthodes de base ou vous pouvez les implémenter dans la classe de base
  4. Les méthodes du contrôleur peuvent ensuite appeler des méthodes dans les classes d'accès aux données selon les besoins.
19
rameshpa

FWIW, concernant les mises à jour dans un environnement multithread:

  • MongoTemplate fournit updateFirst, updateMulti, findAndModify, upsert .. méthodes permettant de modifier un document en une seule opération. L'objet Update utilisé par ces méthodes vous permet également de ne cibler que les champs pertinents.
  • MongoRepository ne vous donne que les opérations de base find, insert, save, delete, qui fonctionnent avec POJO contenant tous les champs. Cela vous oblige à mettre à jour les documents en plusieurs étapes (find le document à mettre à jour, à modifier les champs pertinents à partir du POJO renvoyé, puis à save it), ou à définir vos propres requêtes de mise à jour par main en utilisant @Query.

Dans un environnement multi-thread, comme par exemple a Java back-end avec plusieurs REST points de terminaison, les mises à jour à une seule méthode sont la solution à privilégier, afin de réduire les risques que deux mises à jour simultanées en écrasent une les changements d'un autre.

Exemple: donné un document comme celui-ci: { _id: "ID1", field1: "a string", field2: 10.0 } et deux threads différents le mettant simultanément à jour ...

Avec MongoTemplate, cela ressemblerait un peu à ceci:

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

et l'état final du document est toujours { _id: "ID1", field1: "another string", field2: 15.0 } puisque chaque thread accède au DB une seule fois et seul le champ spécifié est modifié.

Alors que le même scénario avec MongoRepository ressemblerait à ceci:

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)
|                                                               |
|                                                               |

et le document final étant soit { _id: "ID1", field1: "another string", field2: 10.0 } ou { _id: "ID1", field1: "a string", field2: 15.0 } selon l'opération save qui frappe le DB en premier.

Donc, je dirais que MongoTemplate est une meilleure option , sauf si vous avez un modèle POJO très élaboré ou avez besoin des capacités de requête personnalisées de MongoRepository pour une raison quelconque.

9
walen