119 votes

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 j'ai eu du mal à trouver des exemples de requêtes complexes ou à 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é par tâtonnement parce que je n'arrive pas à maîtriser la syntaxe. Même après avoir lu la documentation de mongodb (exemple non fonctionnel à cause de la mauvaise syntaxe).

@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 est bien mieux documenté que MongoRepository . Je me réfère à la documentation suivante :

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

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

164voto

Oliver Gierke Points 11630

"Pratique" et "puissant à utiliser" sont des objectifs contradictoires dans une certaine mesure. Les référentiels sont de loin plus pratiques que les modèles, mais ces derniers vous permettent bien sûr de contrôler plus finement ce qui doit être exécuté.

Comme le modèle de programmation de référentiel est disponible pour plusieurs modules Spring Data, vous trouverez une documentation plus approfondie à ce sujet dans la section générale de la documentation Spring Data MongoDB. documents de référence .

TL;DR

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

  1. Commencez par l'abstrait du référentiel et déclarez simplement des requêtes simples en utilisant le mécanisme de dérivation des requêtes ou des 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 à 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 nommage 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. Maintenant, laissez votre interface de référentiel de base étendre l'interface personnalisée et l'infrastructure utilisera automatiquement votre implémentation personnalisée :

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

De cette façon, vous avez essentiellement le choix : tout ce qui est facile à déclarer va dans UserRepository tout ce qui peut être mieux mis en œuvre manuellement est mis dans CustomUserRepository . Les options de personnalisation sont documentées aquí .

40voto

Luis G. Points 3247

Pour information, concernant les mises à jour dans un environnement multithread :

  • MongoTemplate fournit des opérations "atomiques" prêtes à l'emploi updateFirst , updateMulti , findAndModify , upsert ... qui vous permettent de modifier un document en une seule opération. Le site Update utilisé par ces méthodes vous permet de cibler uniquement les champs pertinents .
  • MongoRepository ne vous donne que le opérations CRUD de base find , insert , save , delete qui fonctionnent avec les POJO contenant tous les champs . Cela vous oblige soit à mettre à jour les documents en plusieurs étapes (1. find le document à mettre à jour, 2. modifier les champs pertinents à partir du POJO retourné, puis 3. save ), ou définissez vos propres requêtes de mise à jour à la main à l'aide de la fonction @Query .

Dans un environnement multithread, comme par exemple un back-end Java avec plusieurs points d'accès REST, les mises à jour à méthode unique sont la meilleure solution, afin de réduire les risques que deux mises à jour simultanées écrasent les changements de l'autre.

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

Avec MongoTemplate ça ressemblerait un peu à ça :

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 n'accède à la base de données qu'une seule fois. y 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 } o { _id: "ID1", field1: "a string", field2: 15.0 } en fonction des save L'opération frappe la BD en dernier.
(NOTE : Même si nous avons utilisé <a href="https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo-template.optimistic-locking" rel="noreferrer">Le programme de Spring Data code>@Version</code annotation </a>comme suggéré dans les commentaires, peu de choses changeraient : l'une des <code>save</code> lanceraient un <code>OptimisticLockingFailureException</code> et le document final serait toujours l'un des documents ci-dessus, avec un seul champ mis à jour au lieu des deux).

Donc je dirais que MongoTemplate est une meilleure option à moins que vous n'ayez un modèle POJO très élaboré ou que vous ayez besoin des capacités de requêtes personnalisées de l'application MongoRepository pour une raison quelconque.

31voto

rameshpa Points 331

Cette réponse peut être un peu tardive, mais je recommanderais d'éviter toute la route du dépôt. Vous obtenez très peu de méthodes implémentées d'une grande valeur pratique. Pour le faire fonctionner, vous vous heurtez aux absurdités de la configuration Java sur lesquelles vous pouvez passer des jours et des semaines sans que la documentation ne vous aide vraiment.

Au lieu de cela, optez pour le MongoTemplate et créer votre propre couche d'accès aux données, ce qui vous libère des cauchemars de configuration auxquels sont confrontés les programmeurs de Spring. MongoTemplate est vraiment le sauveur pour les ingénieurs qui sont à l'aise pour architecturer leurs propres classes et interactions car il y a beaucoup de flexibilité. La structure peut être quelque chose comme ceci :

  1. Créer un MongoClientFactory qui s'exécutera au niveau de l'application et qui vous donnera une MongoClient objet. Vous pouvez l'implémenter en tant que Singleton ou en utilisant un Singleton Enum (ce qui 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 mettre en œuvre une méthode de création d'un objet MongoTemplate que les méthodes spécifiques de votre classe peuvent utiliser 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 mettre en œuvre les méthodes de base ou vous pouvez les mettre en œuvre dans la classe de base.
  4. Les méthodes du contrôleur peuvent ensuite appeler les méthodes des classes d'accès aux données, selon les besoins.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X