MongoTemplate과 MongoRepository의 차이점
편리함(Convenient)과 강력한 사용성(powerful to use)은 어느 정도 상반되는 목표를 가집니다. 편리하다면 그만큼 세심한 부분을 일일이 제어하여 성능적인 부분을 조절하는데 강력함이 떨어질 수 있지만, 반대로 너무 모든 것을 제어하는 것은 오히려 불편함을 생성합니다. 상대적으로 repository는 template보다 더 편리하다는 장점이 있지만 template은 repository보다 더 세밀한 제어가 가능합니다.
repository는 spring data의 주요 프로그래밍 모델로 사용됩니다.
둘 중 뭐가 더 좋은가요?
MongoTemplate과 MongoRepository 중 한가지만을 사용하여 모든 Data Access를 처리하기에 각자의 어려운 점이 존재할 수 있습니다. Template만을 사용한다면 repository에서 제공하는 기본적인 CRUD나 find 메서드, sort와 pagnation에 대한 동적인 Query Derivation 기능이 제공되지 않기에, 이러한 부분은 일일이 구현해야만 합니다.
반대로, repository를 사용한다면 기본적인 기능들은 Spring Data에서 제공하는 Query Derivation으로 이용가능합니다. 하지만 세밀한 제어가 필요하거나 복잡한 수준의 쿼리에 대해 모든 것을 커버해주지 못합니다. 이럴 때는 다시 template이 필요하겠지요.
Spring Data docs에서는 다음과 같은 상황에 template과 repository의 장점을 모두 가져와 이용할 수 있는 custom repository implements 구현을 추천합니다.
Custom Implementations for Spring Data Repositories
Query Method에 다른 동작이 정의되어야 하거나 Query Derivation 만으로 구현할 수 없는 경우 custom implmentations이 필요합니다. Spring Data Repository 기능을 이용한다면 custom repository code와 일반 CRUD 추상화 쿼리 메서드를 함께 제공할 수 있습니다.
Custom Repository 구현 방법
1. Interface for custom repository functionality
우선적으로 custom interface를 생성하고 새롭게 제공할 기능에 대한 메서드를 선언합니다. 이때 custom interface는 fragment interface라고 부릅니다.
interface CustomizedUserRepository {
void someCustomMethod(User user);
}
2. Implementation of custom repository functionality
Fragment interface에 대한 구현 클래스를 생성하고 implements 합니다. 여기서 가장 중요한 점은 구현 클래스의 이름이 Fragment Interface 이름 뒤 Impl 가 postfix로 붙은 이름만 가능하다는 것입니다.
- CustomizedUserRepository (Fragment interface) → CustomizedUserRepositoryImpl (Implment class)
interface CustomizedUserRepositoryImpl extends CustomizedUserRepositoryImpl {
@Autowired
private MongoTemplate mongoTemplate;
public void someCustomeMethod(User user) {
// Custom implementation using mongoTemplate
}
}
3. Changes to your repository interface
마지막으로 repository interface가 CrudRepository와 Fragment Interface를 함께 상속하도록 합니다.
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {
// Declare query methods here
}
Repository interface가 fragment interface를 상속하도록 함으로 CRUD와 사용자 지정 기능이 결합되어 클라이언트가 두 방법에 대하여 모두 사용할 수 있습니다. Fragments는 base repository이자 custom interface이자 functional aspects입니다. 매번 custom interface가 추가되어야 한다면 새로운 fragment를 만들어 상속하게 함으로써 손쉬운 확장이 가능합니다.
Spring Data의 사용을 시작하려는 분들에게는 다음과 같은 과정을 추천드립니다
- 우선적으로 spring data에서 제공하는 repository 통해 base repositorty를 생성합니다. CRUD 또는 naming convention에 맞는 간단한 쿼리를 선언하여 동적으로 제공될 수 있는 쿼리를 사용합니다.
- Spring Data가 지원하는 Query Derivation으로 구현될 수 없을 수준의 복잡한 쿼리들에 대해서 custom interface(fragment)를 생성하고 이를 구현한 Impl 클래스에서 MongoTemplate을 사용하여 직접 구현합니다.
※ 참고자료