Muszę napisać aplikację, w której będę mógł wykonywać złożone zapytania przy użyciu spring-data i mongodb. Zaczynałem od korzystania z MongoRepository, ale zmagałem się ze złożonymi zapytaniami, aby znaleźć przykłady lub faktycznie zrozumieć składnię.
Mówię o zapytaniach takich jak to:
@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrLastName(String email, String lastName);
}
lub użycie zapytań opartych na JSON, które próbowałem metodą prób i błędów, ponieważ nie rozumiem właściwej składni. Nawet po przeczytaniu dokumentacji mongodb (niedziałający przykład z powodu złej składni).
@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);
}
Po przeczytaniu całej dokumentacji wydaje się, że mongoTemplate
jest ona wtedy znacznie lepiej udokumentowana MongoRepository
. Mam na myśli następującą dokumentację:
http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/
Czy możesz mi powiedzieć, co jest wygodniejsze i wydajniejsze w użyciu? mongoTemplate
czy MongoRepository
? Czy oboje są tak samo dojrzali, czy jednemu z nich brakuje więcej funkcji niż drugiemu?
źródło
YourRepository
klasę implementacjiYourRepositoryImpl
. Czy tak jest? Jeśli tak, z przyjemnościąCustomUserRepository
a nieCustomerUserRepository
.Ta odpowiedź może być nieco opóźniona, ale radziłbym omijać całą trasę repozytorium. Otrzymujesz bardzo mało wdrożonych metod o dużej wartości praktycznej. Aby to zadziałało, napotykasz bzdury dotyczące konfiguracji Javy, nad którymi możesz spędzać dni i tygodnie bez większej pomocy w dokumentacji.
Zamiast tego idź z
MongoTemplate
trasą i utwórz własną warstwę dostępu do danych, która uwolni Cię od koszmarów konfiguracyjnych, z którymi borykają się programiści Spring.MongoTemplate
jest naprawdę zbawieniem dla inżynierów, którzy czują się komfortowo przy tworzeniu własnych klas i interakcji, ponieważ zapewnia dużą elastyczność. Struktura może wyglądać mniej więcej tak:MongoClientFactory
klasę, która będzie działać na poziomie aplikacji i da ciMongoClient
obiekt. Możesz zaimplementować to jako Singleton lub używając Enum Singleton (jest to bezpieczne wątkowo)źródło
FWIW, dotyczące aktualizacji w środowisku wielowątkowym:
MongoTemplate
zapewnia „atomowy” out-of-the-box operacjeupdateFirst
,updateMulti
,findAndModify
,upsert
..., które pozwalają modyfikować dokument w jednej operacji.Update
Obiekt używany przez tych metod również pozwala kierować tylko odpowiednie pola .MongoRepository
tylko daje podstawowe operacje CRUDfind
,insert
,save
,delete
, które pracują z POJOs zawierających wszystkie pola . Wymusza to albo aktualizację dokumentów w kilku krokach (1.find
dokument do aktualizacji, 2. modyfikacja odpowiednich pól ze zwróconego POJO, a następnie 3.save
to), albo ręczne zdefiniowanie własnych zapytań aktualizacyjnych@Query
.W środowisku wielowątkowym, takim jak np. Zaplecze Java z kilkoma punktami końcowymi REST, najlepszym rozwiązaniem są aktualizacje przy użyciu jednej metody, aby zmniejszyć prawdopodobieństwo, że dwie równoległe aktualizacje nadpisują nawzajem zmiany.
Przykład: mając taki dokument:
{ _id: "ID1", field1: "a string", field2: 10.0 }
i dwa różne wątki jednocześnie go aktualizujące ...Dzięki
MongoTemplate
temu wyglądałoby to mniej więcej tak:THREAD_001 THREAD_002 | | |update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5)) | | | |
a ostatecznym stanem dokumentu jest zawsze,
{ _id: "ID1", field1: "another string", field2: 15.0 }
ponieważ każdy wątek uzyskuje dostęp do bazy danych tylko raz i tylko określone pole jest zmieniane.Podczas gdy ten sam scenariusz z
MongoRepository
wyglądałby tak: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) | | | |
a końcowy dokument jest albo
{ _id: "ID1", field1: "another string", field2: 10.0 }
czy{ _id: "ID1", field1: "a string", field2: 15.0 }
w zależności odsave
operacji uderza DB ostatni.(UWAGA: Nawet gdybyśmy użyli adnotacji Spring Data,
@Version
jak sugerowano w komentarzach, niewiele by się zmieniło: jedna zsave
operacji wyrzuciłabyOptimisticLockingFailureException
, a dokument końcowy byłby nadal jednym z powyższych, z zaktualizowanym tylko jednym polem zamiast obu. )Więc powiedziałbym, że
MongoTemplate
jest to lepsza opcja , chyba że masz bardzo rozbudowany model POJO lub zMongoRepository
jakiegoś powodu potrzebujesz niestandardowych możliwości zapytań .źródło
@Version
czy „uniknie” drugiego wątku nadpisującego dane zapisane przez pierwszy - „uniknie” w tym sensie, że odrzuci aktualizację iOptimisticLockingFailureException
zamiast tego wyrzuci . Więc jeśli chcesz, aby aktualizacja się powiodła, musisz zaimplementować mechanizm ponawiania. MongoTemplate pozwala ominąć cały scenariusz.