스프링 데이터와 mongodb를 사용하여 복잡한 쿼리를 수행 할 수있는 애플리케이션을 작성해야합니다. MongoRepository를 사용하여 시작했지만 예제를 찾거나 실제로 구문을 이해하기 위해 복잡한 쿼리로 어려움을 겪었습니다.
나는 다음과 같은 쿼리에 대해 이야기하고 있습니다.
@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrLastName(String email, String lastName);
}
또는 구문이 잘못 되었기 때문에 시행 착오를 거쳐 시도한 JSON 기반 쿼리 사용. mongodb 문서를 읽은 후에도 (잘못된 구문으로 인해 작동하지 않는 예제).
@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);
}
모든 문서를 읽은 후에는 문서화 mongoTemplate
가 훨씬 더 나은 것 같습니다 MongoRepository
. 다음 문서를 참조하고 있습니다.
http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/
사용하기 더 편리하고 강력한 것이 무엇인지 말씀해 주시겠습니까? mongoTemplate
또는 MongoRepository
? 둘 다 똑같습니까, 아니면 둘 중 하나가 다른 것보다 더 많은 기능이 부족합니까?
답변
“편리함”과 “사용하기 강력 함”은 어느 정도 상반되는 목표입니다. 리포지토리는 템플릿보다 훨씬 편리하지만 물론 후자는 실행할 항목을보다 세밀하게 제어 할 수 있습니다.
저장소 프로그래밍 모델은 여러 SpringData 모듈에서 사용할 수 있으므로 SpringData MongoDB 참조 문서 의 일반 섹션에서 더 자세한 문서를 찾을 수 있습니다 .
TL; DR
일반적으로 다음 접근 방식을 권장합니다.
- 저장소 추상으로 시작하고 쿼리 파생 메커니즘 또는 수동으로 정의 된 쿼리를 사용하여 간단한 쿼리를 선언하십시오.
- 더 복잡한 쿼리의 경우 수동으로 구현 된 메서드를 저장소에 추가합니다 (여기에 설명 된대로). 구현을 위해
MongoTemplate
.
세부
귀하의 예를 들어 이것은 다음과 같습니다.
-
사용자 정의 코드에 대한 인터페이스를 정의하십시오.
interface CustomUserRepository { List<User> yourCustomMethod(); }
-
이 클래스에 대한 구현을 추가하고 이름 지정 규칙을 따라 클래스를 찾을 수 있는지 확인하십시오.
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 } }
-
이제 기본 저장소 인터페이스가 사용자 정의 인터페이스를 확장하도록하면 인프라가 사용자 정의 구현을 자동으로 사용합니다.
interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository { }
이렇게하면 본질적으로 선택할 수 있습니다. 선언하기 쉬운 UserRepository
모든 것은에 들어가고 , 더 잘 구현 된 모든 것은에 들어가게됩니다 CustomUserRepository
. 사용자 정의 옵션은 여기 에 설명되어 있습니다 .
답변
이 답변은 약간 지연 될 수 있지만 전체 저장소 경로를 피하는 것이 좋습니다. 실질적인 가치가있는 구현 방법은 거의 없습니다. 그것을 작동시키기 위해 당신은 문서에서 많은 도움없이 며칠과 몇 주를 보낼 수있는 자바 구성의 말도 안되는 상황에 빠진다.
대신, MongoTemplate
경로 를 따라 가서 Spring 프로그래머가 직면 한 구성 악몽에서 벗어날 수있는 고유 한 데이터 액세스 레이어를 만드십시오. MongoTemplate
많은 유연성이 있기 때문에 자신의 수업과 상호 작용을 편안하게 설계하는 엔지니어에게 정말 구세주입니다. 구조는 다음과 같을 수 있습니다.
MongoClientFactory
응용 프로그램 수준에서 실행되고MongoClient
개체를 제공 할 클래스를 만듭니다 . 이것을 Singleton으로 구현하거나 Enum Singleton을 사용하여 구현할 수 있습니다 (스레드 안전).- 각 도메인 개체에 대한 데이터 액세스 개체를 상속 할 수있는 데이터 액세스 기본 클래스를 만듭니다. 기본 클래스는 특정 메서드가 모든 DB 액세스에 사용할 수있는 MongoTemplate 객체를 생성하는 메서드를 구현할 수 있습니다.
- 각 도메인 개체의 각 데이터 액세스 클래스는 기본 메서드를 구현하거나 기본 클래스에서 구현할 수 있습니다.
- 그런 다음 Controller 메서드는 필요에 따라 Data 액세스 클래스의 메서드를 호출 할 수 있습니다.
답변
FWIW, 다중 스레드 환경의 업데이트 관련 :
MongoTemplate
제공 “원자”아웃 – 오브 – 박스 작업updateFirst
,updateMulti
,findAndModify
,upsert
… 당신은 한 번의 작업으로 문서를 수정할 수 있습니다.Update
이러한 방법에 의해 사용되는 객체는 만 관련 분야를 대상으로 할 수 있습니다 .MongoRepository
단지 당신에게 제공 기본 CRUD 작업을find
,insert
,save
,delete
, 포함하여 POJO로 작동하는 모든 필드를 . 이렇게하면 여러 단계 (1. 업데이트 할 문서find
, 2. 반환 된 POJO에서 관련 필드 수정, 3. 수정)에서 문서를 업데이트save
하거나를 사용하여 직접 업데이트 쿼리를 정의해야합니다@Query
.
예를 들어 여러 REST 엔드 포인트가있는 Java 백엔드와 같은 다중 스레드 환경에서는 두 개의 동시 업데이트가 서로의 변경 사항을 덮어 쓸 가능성을 줄이기 위해 단일 방법 업데이트를 사용하는 것이 좋습니다.
예 : 다음과 같은 문서가 주어 { _id: "ID1", field1: "a string", field2: 10.0 }
지고 두 개의 다른 스레드가 동시에 업데이트합니다.
다음과 MongoTemplate
같이 보일 것입니다.
THREAD_001 THREAD_002
| |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
| |
| |
그리고 문서의 최종 상태는 항상 { _id: "ID1", field1: "another string", field2: 15.0 }
각 스레드가 DB에 한 번만 액세스 하고 지정된 필드 만 변경되기 때문입니다.
와 동일한 케이스 시나리오 MongoRepository
는 다음과 같습니다.
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)
| |
| |
최종 문서 는 DB에 마지막 으로 도달하는 작업 에 따라 { _id: "ID1", field1: "another string", field2: 10.0 }
또는
(참고 : 주석 에서 제안한대로 SpringData 의 주석 을 사용하더라도 크게 변경되지는 않습니다. 작업 중 하나 가를 throw 하고 최종 문서는 여전히 위의 하나이며 둘 다 대신 하나의 필드 만 업데이트됩니다. ){ _id: "ID1", field1: "a string", field2: 15.0 }
save
@Version
save
OptimisticLockingFailureException
따라서 매우 정교한 POJO 모델이 있거나 어떤 이유로 든 의 사용자 지정 쿼리 기능이 필요하지 않는 한 MongoTemplate
이것이 더 나은 옵션 이라고 말하고 싶습니다 MongoRepository
.