java - conectar - ¿Cuál es la diferencia entre MongoTemplate y MongoRepository de Spring Data?
spring data mongodb query (3)
Necesito escribir una aplicación con la cual pueda hacer consultas complejas usando spring-data y mongodb. Empecé utilizando el MongoRepository, pero tuve problemas con las consultas complejas para encontrar ejemplos o comprender realmente la sintaxis.
Estoy hablando de consultas como esta:
@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrLastName(String email, String lastName);
}
o el uso de consultas basadas en JSON que probé por prueba y error porque no obtengo la sintaxis correcta. Incluso después de leer la documentación de mongodb (ejemplo que no funciona debido a una sintaxis incorrecta).
@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);
}
Después de leer toda la documentación, parece que mongoTemplate
está mucho mejor documentado que MongoRepository
. Me refiero a la siguiente documentación:
http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/
¿Puede decirme qué es más conveniente y poderoso de usar? mongoTemplate
o MongoRepository
? ¿Ambos son iguales o uno de ellos no tiene más características que el otro?
"Conveniente" y "poderoso de usar" son objetivos contradictorios hasta cierto punto. Los repositorios son mucho más convenientes que las plantillas, pero estas últimas, por supuesto, le dan un control más preciso sobre qué ejecutar.
Como el modelo de programación de repositorios está disponible para múltiples módulos de Spring Data, encontrará más documentación exhaustiva en la sección general de los documentos de referencia de Spring Data MongoDB.
TL; DR
En general, recomendamos el siguiente enfoque:
- Comience con el resumen del repositorio y simplemente declare consultas simples utilizando el mecanismo de derivación de la consulta o las consultas definidas manualmente.
- Para consultas más complejas, agregue métodos implementados manualmente al repositorio (como se documenta aquí). Para la implementación use
MongoTemplate
.
Detalles
Para su ejemplo, esto se vería así:
Defina una interfaz para su código personalizado:
interface CustomUserRepository { List<User> yourCustomMethod(); }
Agregue una implementación para esta clase y siga la convención de nomenclatura para asegurarse de que podamos encontrar la clase.
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 } }
Ahora permita que su interfaz de repositorio base amplíe la personalizada y la infraestructura usará automáticamente su implementación personalizada:
interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository { }
De esta manera, esencialmente tiene la opción: todo lo que es fácil de declarar entra en el UserRepository
, todo lo que se implementa mejor manualmente va a CustomUserRepository
. Las opciones de personalización están documentadas here .
Esta respuesta puede demorarse un poco, pero recomendaría evitar toda la ruta del repositorio. Obtienes muy pocos métodos implementados de gran valor práctico. Para que funcione, se encuentra con la tontería de la configuración de Java, que puede pasar días y semanas sin mucha ayuda en la documentación.
En su lugar, vaya con la ruta MongoTemplate
y cree su propia capa de acceso a datos que lo libere de las pesadillas de configuración que enfrentan los programadores de Spring. MongoTemplate
es realmente el salvador para los ingenieros que se sienten cómodos diseñando sus propias clases e interacciones ya que hay mucha flexibilidad. La estructura puede ser algo como esto:
- Cree una clase
MongoClientFactory
que se ejecutará en el nivel de la aplicación y le proporcionará un objetoMongoClient
. Puede implementar esto como Singleton o usando un Enum Singleton (esto es seguro para subprocesos) - Cree una clase base de acceso a Datos desde la cual puede heredar un objeto de acceso a datos para cada objeto de dominio). La clase base puede implementar un método para crear un objeto MongoTemplate que los métodos específicos de la clase puedan usar para todos los accesos a bases de datos.
- Cada clase de acceso a datos para cada objeto de dominio puede implementar los métodos básicos o puede implementarlos en la clase base
- Los métodos de controlador pueden llamar a los métodos en las clases de acceso a datos según sea necesario.
FWIW, con respecto a las actualizaciones en un entorno de subprocesos múltiples:
-
MongoTemplate
proporcionaMongoTemplate
paraupdateFirst
,updateMulti
,findAndModify
,upsert
... métodos que le permiten modificar un documento en una sola operación. El objetoUpdate
utilizado por estos métodos también le permite orientar solo los campos relevantes. -
MongoRepository
solo le ofrece las operaciones básicas defind
,insert
,MongoRepository
ydelete
, que funcionan con POJO que contienen todos los campos. Esto lo obliga a actualizar los documentos en varios pasos (find
el documento para actualizar, modifique los campos relevantes del POJO devuelto y luegosave
) o defina sus propias consultas de actualización manualmente usando@Query
.
En un entorno de subprocesos múltiples, como por ejemplo un back-end de Java con varios puntos finales REST, las actualizaciones de método único son el camino a seguir, a fin de reducir las posibilidades de que dos actualizaciones simultáneas se sobrescriban entre sí.
Ejemplo: dado un documento como este: { _id: "ID1", field1: "a string", field2: 10.0 }
y dos hilos diferentes actualizándolo al mismo tiempo ...
Con MongoTemplate
se vería algo así:
THREAD_001 THREAD_002
| |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
| |
| |
y el estado final para el documento siempre es { _id: "ID1", field1: "another string", field2: 15.0 }
ya que cada hilo accede al DB solo una vez y solo se cambia el campo especificado.
Mientras que el mismo escenario de MongoRepository
se vería así:
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)
| |
| |
y el documento final es { _id: "ID1", field1: "another string", field2: 10.0 }
o { _id: "ID1", field1: "a string", field2: 15.0 }
dependiendo de la operación de save
que { _id: "ID1", field1: "a string", field2: 15.0 }
al DB primero.
Entonces, diría que MongoTemplate
es una mejor opción , a menos que tenga un modelo POJO muy elaborado o necesite las capacidades de consultas personalizadas de MongoRepository
por algún motivo.