[java] SpringData의 MongoTemplate과 MongoRepository의 차이점은 무엇입니까?

스프링 데이터와 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

일반적으로 다음 접근 방식을 권장합니다.

  1. 저장소 추상으로 시작하고 쿼리 파생 메커니즘 또는 수동으로 정의 된 쿼리를 사용하여 간단한 쿼리를 선언하십시오.
  2. 더 복잡한 쿼리의 경우 수동으로 구현 된 메서드를 저장소에 추가합니다 (여기에 설명 된대로). 구현을 위해 MongoTemplate.

세부

귀하의 예를 들어 이것은 다음과 같습니다.

  1. 사용자 정의 코드에 대한 인터페이스를 정의하십시오.

    interface CustomUserRepository {
    
      List<User> yourCustomMethod();
    }
  2. 이 클래스에 대한 구현을 추가하고 이름 지정 규칙을 따라 클래스를 찾을 수 있는지 확인하십시오.

    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. 이제 기본 저장소 인터페이스가 사용자 정의 인터페이스를 확장하도록하면 인프라가 사용자 정의 구현을 자동으로 사용합니다.

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

이렇게하면 본질적으로 선택할 수 있습니다. 선언하기 쉬운 UserRepository모든 것은에 들어가고 , 더 잘 구현 된 모든 것은에 들어가게됩니다 CustomUserRepository. 사용자 정의 옵션은 여기 에 설명되어 있습니다 .


답변

이 답변은 약간 지연 될 수 있지만 전체 저장소 경로를 피하는 것이 좋습니다. 실질적인 가치가있는 구현 방법은 거의 없습니다. 그것을 작동시키기 위해 당신은 문서에서 많은 도움없이 며칠과 몇 주를 보낼 수있는 자바 구성의 말도 안되는 상황에 빠진다.

대신, MongoTemplate경로 를 따라 가서 Spring 프로그래머가 직면 한 구성 악몽에서 벗어날 수있는 고유 한 데이터 액세스 레이어를 만드십시오. MongoTemplate많은 유연성이 있기 때문에 자신의 수업과 상호 작용을 편안하게 설계하는 엔지니어에게 정말 구세주입니다. 구조는 다음과 같을 수 있습니다.

  1. MongoClientFactory응용 프로그램 수준에서 실행되고 MongoClient개체를 제공 할 클래스를 만듭니다 . 이것을 Singleton으로 구현하거나 Enum Singleton을 사용하여 구현할 수 있습니다 (스레드 안전).
  2. 각 도메인 개체에 대한 데이터 액세스 개체를 상속 할 수있는 데이터 액세스 기본 클래스를 만듭니다. 기본 클래스는 특정 메서드가 모든 DB 액세스에 사용할 수있는 MongoTemplate 객체를 생성하는 메서드를 구현할 수 있습니다.
  3. 각 도메인 개체의 각 데이터 액세스 클래스는 기본 메서드를 구현하거나 기본 클래스에서 구현할 수 있습니다.
  4. 그런 다음 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
@VersionsaveOptimisticLockingFailureException

따라서 매우 정교한 POJO 모델이 있거나 어떤 이유로 든 의 사용자 지정 쿼리 기능이 필요하지 않는 한 MongoTemplate이것이 더 나은 옵션 이라고 말하고 싶습니다 MongoRepository.


답변