it-swarm.com.de

Was ist der Unterschied zwischen MongoTemplate und MongoRepository von Spring Data?

Ich muss eine Anwendung schreiben, mit der ich komplexe Abfragen mit spring-data und mongodb ausführen kann. Ich habe angefangen, das MongoRepository zu verwenden, hatte jedoch Probleme mit komplexen Abfragen, um Beispiele zu finden oder die Syntax tatsächlich zu verstehen.

Ich spreche über Fragen wie diese:

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

oder die Verwendung von JSON-basierten Abfragen, die ich durch Ausprobieren ausprobiert habe, weil ich die Syntax nicht richtig verstehe. Auch nach dem Lesen der Mongodb-Dokumentation (nicht funktionierendes Beispiel aufgrund falscher Syntax).

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

Nach dem Lesen der gesamten Dokumentation scheint es, dass mongoTemplate weitaus besser dokumentiert ist als MongoRepository. Ich beziehe mich auf folgende Dokumentation:

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

Können Sie mir sagen, was bequemer und leistungsfähiger ist? mongoTemplate oder MongoRepository? Sind beide gleich ausgereift oder fehlt einem mehr als dem anderen?

77

"Praktisch" und "leistungsstark" stehen in gewissem Widerspruch zu den Zielen. Repositorys sind weitaus praktischer als die Vorlagen, aber letztere bieten Ihnen natürlich eine genauere Kontrolle darüber, was ausgeführt werden soll.

Da das Repository-Programmiermodell für mehrere Spring Data-Module verfügbar ist, finden Sie eine ausführlichere Dokumentation im allgemeinen Abschnitt der Spring Data MongoDB Referenzdokumente .

TL; DR

Generell empfehlen wir folgende Vorgehensweise:

  1. Beginnen Sie mit der Zusammenfassung des Repositorys und deklarieren Sie einfach einfache Abfragen mithilfe des Ableitungsmechanismus für Abfragen oder manuell definierter Abfragen.
  2. Fügen Sie für komplexere Abfragen manuell implementierte Methoden zum Repository hinzu (wie hier dokumentiert). Für die Implementierung verwenden Sie MongoTemplate.

Details

Für Ihr Beispiel würde dies ungefähr so ​​aussehen:

  1. Definieren Sie eine Schnittstelle für Ihren benutzerdefinierten Code:

    interface CustomUserRepository {
    
      List<User> yourCustomMethod();
    }
    
  2. Fügen Sie eine Implementierung für diese Klasse hinzu und befolgen Sie die Namenskonvention, um sicherzustellen, dass die Klasse gefunden wird.

    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. Lassen Sie nun Ihre Basis-Repository-Schnittstelle die benutzerdefinierte Schnittstelle erweitern, und die Infrastruktur verwendet automatisch Ihre benutzerdefinierte Implementierung:

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

Auf diese Weise haben Sie im Wesentlichen die Wahl: Alles, was einfach zu deklarieren ist, geht in UserRepository, alles, was besser manuell implementiert wird, geht in CustomUserRepository. Die Anpassungsoptionen sind dokumentiert hier .

118
Oliver Drotbohm

Diese Antwort kann etwas verzögert sein, ich würde jedoch empfehlen, die gesamte Repository-Route zu vermeiden. Sie erhalten sehr wenig implementierte Methoden von großem praktischen Wert. Damit es funktioniert, stoßen Sie auf den Java) - Konfigurationsquatsch, mit dem Sie Tage und Wochen ohne viel Hilfe in der Dokumentation verbringen können.

Wechseln Sie stattdessen zur Route MongoTemplate und erstellen Sie eine eigene Datenzugriffsebene, die Sie von den Konfigurations-Albträumen befreit, mit denen Spring-Programmierer konfrontiert sind. MongoTemplate ist wirklich der Retter für Ingenieure, die gerne ihre eigenen Klassen und Interaktionen entwerfen, da es viel Flexibilität gibt. Die Struktur kann ungefähr so ​​aussehen:

  1. Erstellen Sie eine MongoClientFactory -Klasse, die auf Anwendungsebene ausgeführt wird, und geben Sie ein MongoClient -Objekt an. Sie können dies als Singleton oder mit einem Enum Singleton implementieren (dies ist threadsicher)
  2. Erstellen Sie eine Datenbankklasse, von der Sie ein Datenzugriffsobjekt für jedes Domänenobjekt erben können. Die Basisklasse kann eine Methode zum Erstellen eines MongoTemplate-Objekts implementieren, die Sie klassenspezifisch für alle DB-Zugriffe verwenden können
  3. Jede Datenzugriffsklasse für jedes Domänenobjekt kann die grundlegenden Methoden implementieren oder Sie können sie in der Basisklasse implementieren
  4. Die Controller-Methoden können dann nach Bedarf Methoden in den Datenzugriffsklassen aufrufen.
19
rameshpa

FWIW in Bezug auf Updates in einer Umgebung mit mehreren Threads:

  • MongoTemplate bietet standardmäßig updateFirst, updateMulti, findAndModify [$ var] _, upsert .. Methoden, mit denen Sie ein Dokument in einer einzigen Operation ändern können. Mit dem von diesen Methoden verwendeten Objekt Update können Sie auch nur die relevanten Felder als Ziel festlegen.
  • MongoRepository gibt Ihnen nur die grundlegenden find, insert, save, delete Operationen, mit denen Sie arbeiten POJOs, die alle Felder enthalten. Dies zwingt Sie entweder dazu, die Dokumente in mehreren Schritten zu aktualisieren (find das zu aktualisierende Dokument, die entsprechenden Felder aus dem zurückgegebenen POJO zu ändern und dann save es) oder Ihre eigenen Aktualisierungsabfragen zu definieren Hand mit @Query.

In einer Umgebung mit mehreren Threads, wie z.B. a Java Back-End mit mehreren REST Endpunkten, Aktualisierungen mit einer Methode sind der richtige Weg, um die Wahrscheinlichkeit zu verringern, dass zwei Aktualisierungen eine Aktualisierung gleichzeitig überschreiben Änderungen eines anderen.

Beispiel: ein Dokument wie dieses gegeben: { _id: "ID1", field1: "a string", field2: 10.0 } und zwei verschiedene Threads, die es gleichzeitig aktualisieren ...

Mit MongoTemplate würde es ungefähr so ​​aussehen:

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

und der Endzustand für das Dokument ist immer { _id: "ID1", field1: "another string", field2: 15.0 } da jeder Thread nur einmal auf den DB zugreift und wird nur das angegebene Feld geändert.

Während das gleiche Szenario mit MongoRepository so aussehen würde:

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

und das endgültige Dokument ist entweder { _id: "ID1", field1: "another string", field2: 10.0 } oder { _id: "ID1", field1: "a string", field2: 15.0 } abhängig davon, welche save Operation zuerst die DB trifft.

Also würde ich sagen, dass MongoTemplate eine bessere Option ist , es sei denn, Sie haben ein sehr ausgearbeitetes POJO-Modell oder benötigen die benutzerdefinierten Abfragemöglichkeiten von MongoRepository aus irgendeinem Grund.

9
walen