이번 글에서는 지난 Spring Boot  + Spring Data MongoDB + MongoRepository Demo 에 이어서

MongoTemplate 를 사용하여 데모 앱을 만들겠습니다.

MongoRepository 과 비교할수 있게 작성해볼 예정이고 어떤 차이가 있는 정리해보겠습니다. 

 

개발 환경 : STS 4.8.1, JDK 11, Spring Boot 2.6.2 Mongo 5.0.5 Community, Maven 4.0.0

 

1. Spring Boot 프로젝트 생성 

Spring Stater Project 생성하고 중간 의존성 설정 단계에서 아래와 같이 설정하고 생성합니다.

프로젝트, 패키지 명은 적절하게 설정해주세요.

저는 SpringbootMongoDbDemo, com.example.demo 라고 설정했습니다.

 

아래와 같은 구조를 가진 프로젝트가 생성된 것을 확인할수있습니다.

Customer 파일은 다음 과정에서 생성할 패키지와 파일들입니다.

 

2. application.properties 파일 설정

설치된 MongoDB는 테스트를 위한 기본 버전으로 username과 password 설정이 없어서 주석처리했습니다.

별도의 Mongo 설정 없이 아래의 설정만으로도 MongoDB에 액세스 가능합니다.

보통 기본 uri가 localhost를 많이 쓰고 database는 미리 test로 생성했습니다.

spring.data.mongodb.uri=mongodb://localhost:27017
spring.data.mongodb.database=test
#spring.data.mongodb.username=
#spring.data.mongodb.passwrod=

 

3. Customer 객체 생성

Spring boot에서 Mongo를 사용 가능한 방법은 스프링 가이드를 참고해보면

크게 2가지 정도인데, 간단한 CRUD 처리는 MongoRepository를 사용하면 되고

조금 복잡한 작업을 위해서는 MongoTemplate 사용하면 됩니다.

이번 글에서는 MongoRepository 로 간략한 CRUD 테스트를 진행해보겠습니다.

package com.example.demo;

import org.springframework.data.annotation.Id;

public class Customer {

	@Id
	public String id;

	public String firstName;
	public String lastName;

	public Customer() {}

	public Customer(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@Override
	public String toString() {
		return String.format(
				"Customer[id=%s, firstName='%s', lastName='%s']",
				id, firstName, lastName);
	}
}

4. CommandLineRunner 생성 및 서버 스타트

자동 생성된 SpringbootMongoDbDemoApplication2.java 파일로 이동하여 CommandLineRunner 구현해줍니다.

Overide된 run 메소드 안에 CRUD 테스트 코드를 작성하고 Boot Dashboard에서 서버를 Start 합니다.

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

@SpringBootApplication
public class SpringbootMongoDbDemo2Application implements CommandLineRunner {

	@Autowired
	private MongoTemplate mongoTemplate;
	
	public static void main(String[] args) {
		SpringApplication.run(SpringbootMongoDbDemo2Application.class, args);
	}
	
	@Override
	public void run(String... args) throws Exception {

		// 최초 실행시 삭제
		mongoTemplate.remove(new Query(), "customer");
		
		// Customer 객체 생성
		Customer Bob = new Customer("Bob", "Smith");
		Customer John = new Customer("John", "Smith");
		Customer Alice = new Customer("Alice", "Smith");
		
		// mongoDB에 insert 수행. insert 메소드로 대체 가능하나 차이가 있음.
		mongoTemplate.save(Bob);
		mongoTemplate.save(John);
		mongoTemplate.save(Alice);
		
		// mongoDB에 Update 수행.
		Alice.setFirstName("Alice");
		Alice.setLastName("Chris");
		// upate 메소드로 대체 가능하나 차이가 있음.
		mongoTemplate.save(Alice); 
		
		// mongoDB에 조회 수행.
		Query query = new Query();
		Criteria criteria = Criteria.where("firstName").is("Bob");
		query.addCriteria(criteria);
		Customer temp = mongoTemplate.findOne(query, Customer.class);
		
		// mongoDB에 삭제 수행.
		mongoTemplate.remove(temp);
		
		System.out.println("Customers found with findAll():");
		System.out.println("-------------------------------");
		for (Customer customer : mongoTemplate.findAll(Customer.class)) {
			System.out.println(customer);
		}
		System.out.println();
		
		System.out.println("Customer found with findByFirstName('Alice'):");
		query = new Query(Criteria.where("firstName").is("Alice"));
		System.out.println(mongoTemplate.findOne(query, Customer.class));
		System.out.println("--------------------------------");

		System.out.println("Customers found with findByLastName('Smith'):");
		System.out.println("--------------------------------");
		query = new Query(Criteria.where("lastName").is("Smith"));
		for (Customer customer : mongoTemplate.find(query, Customer.class)) {
			System.out.println(customer);
		}
		
	}
}

 

이전글의 MongoRepository를 extends 하여 구현한 CustomerRepository 의 사용과는 조금 차이가 있지만 동일하게 동작합니다. 가장 큰 차이점은 Query 와 Criteria 객체를 이용하여 query를 만들어 세부적인 제어를 한다는 점인데요.

 

5. MongDB Compass 툴로 데이터 확인

해당 툴은 MongoDB Compass 시 기본 설치되는 툴입니다.

MongoDB Compass 툴로 접속하여 정보를 다시 확인해보겠습니다

 

 

5. Save, Insert, Update

그리고 삽입, 수정을 위해서 save 메소드를 사용했는데요.

삽입의 경우에는 insert 메소드, 수정의 경우에는 update 메소드로 대체 가능합니다.

다만 save 의 사용과 insert, update 사용에는 차이가 있기때문에 모르고 사용했을 경우 크게 낭패를 볼수도 있습니다.

save 메소드의 경우에는 _id 값이 존재하지 않으면 데이터를 삽입하지만 _id 값이 존재하는 경우 데이터가 수정됩니다.

그리고 값을 수정하는 경우에 특정 필드가 아닌 모든 데이터를 덮어쓰므로 만약 업데이트하는 필드 외에  다른 필드 값이 정의되어 있지 않은 객체를 save 메소드로 업데이트 하는 경우 데이터가 초기화 될수있다.

잘 이해가 가지 않는다면 아래의 참고 레퍼런스에서 차이점을 확인해보고 정확히 이해하고 사용할 필요가 있습니다.

 

6. 마치며 

MongoRepository도 @Query 어노테이션을 활용하여 어느정도 MongoTemplate 처럼 세부 제어는 가능하지만 개인적인 생각으로는 실무 환경에서 간단한 CRUD 만 처리하는 기능이 아닌 프로그램을 구현해야한다면 mongoTemplate를 사용하는 것이 좋지 않을까 생각됩니다. 비즈니스 환경에 따라서 고민이 필요한 부분 같습니다.

이번 코드도 Github에서 확인 가능하며, 참고한 아래의 사이트에서 더 자세히 확인 가능합니다.

 

※ 참고 

https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#reference

https://www.baeldung.com/spring-data-mongodb-tutorial

https://www.baeldung.com/queries-in-spring-data-mongodb

https://stackoverflow.com/questions/16209681/what-is-the-difference-between-save-and-insert-in-mongo-db

 

+ Recent posts