[MongoDB] MongoTemplate vs. MongoRepository

rin·2020년 5월 30일
0
post-thumbnail

ref. https://stackoverflow.com/questions/17008947/whats-the-difference-between-spring-datas-mongotemplate-and-mongorepository
스택 오버플로우의 답변을 번역함

repository는 template보다 편리하지만 template은 실행할 질의에 대해 더 세부적인 제어가 가능하다.

여러 스프링 데이터 모듈에 대해 repository 프로그래밍 모델을 사용할 수 있기때문에 spring-data-mongodb reference에 대한 자세한 내용을 확인 할 수 있다.

reference에서는 다음과 같이 설명한다.


JpaRepository나 MongoRepository와 같은 persistence 기술에 대한 특성화된 추상화를 제공한다. 이러한 인터페이스는 CrudRepository를 확장하고 CrudRepository와 같은 다소 일반적인 persistence 기술-불가지론(agnostic)의 인터페이스 외에도 기본적인 persistence 기술의 기능을 사용한다.

일반적으로 다음과 같은 접근법을 권장한다.

  1. repository 추상화
  2. 쿼리 생성 메커니즘 또는 메뉴얼로 정의되어있는 쿼리를 사용해 간단한 쿼리 메소드를 선언한다.
  3. 보다 복잡한 쿼리를 위해 메뉴얼에 따라 구현되어있는 메소드를 레포지토리에 추가한다.
  4. 구현을 위해서 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은 "원자성"을 즉시 사용할 수 있는 연산자인 updateFirst, updateMulti, findAndModify, upsert... 등 단일 작업에서 문서를 수정할 수 있는 기능들을 제공한다. 또한 이런 메소드에 사용되는 업데이트 개체를 사용해 관련 필드만 대상으로 지정할 수 있다.

MongoRepository모든 필드를 포함하는 POJO와 함께 작동하는 기본적인 CRUD 작업만 제공한다. 이렇게하면 여러 단계로 문서를 업데이트하거나 (1. 업데이트 할 문서 찾기, 2. 반환된 POJO에서 관련 필드를 수정한 다음 3. 저장) @Query를 사용해 직접 업데이트 쿼리를 정의해야 한다.

여러 REST 엔드포인트가 있는 Java 백엔드 같은 다중 스레드 환경에서는 동시에 일어나는 두 개의 업데이트가 서로 다른 변경 사항을 덮어쓸 가능성을 줄이기 위해 단일 메소드 업데이트를 사용해야한다. (MongoTemplate의 update기능은 변화할 필드만 지정해서 변경할 수 있다.)

예를 들어 { _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))
|                                                               |
|                                                               |

field1field2에 각각 업데이트가 되기 때문에 결과는 항상 { _id: "ID1", field1: "another string", field2: 15.0 }이다.

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)
|                                                               |
|                                                               |

결과적으로 { _id: "ID1", field1: "another string", field2: 10.0 } 혹은 { _id: "ID1", field1: "a string", field2: 15.0 }로 변경될 것이다. (save는 lock되지 않기 때문에 두 스레드 모두 수정전 데이터인 { _id: "ID1", field1: "a string", field2: 10.0 }를 find 해온다.)

profile
🌱 😈💻 🌱

0개의 댓글