Spring Boot 에서 MongoDB 사용하기

이정민·2024년 1월 19일
0
post-thumbnail
post-custom-banner

Spring Boot 에서 MongoDB Atlas 로 구성한 MongoDB Cluster 에 연결하는 방법을 정리했습니다.


MongoDB 의존성 추가


MongoDB Atlas 연결

  • MongoDB Atlas 를 통한 Cluster 구성 방법은 다른 블로그에도 자세하게 설명되어 있으니 생략하겠습니다.

위 MongoDB 접속 경로는 application.yml 파일에서 사용합니다.


1. MongoRepository 를 사용하는 방법

  • Spring Data JPA 를 통해 MongoRepository 를 사용하는 방법입니다. 간단한 도메인을 만들어 기본적인 동작을 테스트 해보겠습니다.

User

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "user")
public class User {

    @Id
    private String id;
    private String name;
}

UserRepository

    public interface UserRepository extends MongoRepository<User, String> {
}
  • MongoRepository 는 내부적으로 JpaRepository 와 같이 CrudRepository 를 기본적으로 상속받습니다. 따라서 MySQL 과 같은 기존의 RDB 에서 JPA 를 사용하던 방식과 똑같이 사용하면 됩니다.


UserService

  • 기본 CRUD 기능입니다.
@RequiredArgsConstructor
@Service
public class UserService {
    private final UserRepository userRepository;

    public String create(String name) {
        User user = User.builder()
                .name(name)
                .build();

        return userRepository.save(user).getId();
    }

    public User read(String id) {
        return userRepository.findById(id).orElse(null);
    }

    public User update(String id, String name) {
        User user = userRepository.findById(id).orElse(null);

        assert user != null;
        user.setName(name);

        return userRepository.save(user);
    }

    public void delete(String id) {
        userRepository.deleteById(id);
    }
}

UserController

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/v1/user")
public class UserController {
    private final UserService userService;

    @PostMapping("")
    public String create(@RequestParam String name) {
        return userService.create(name);
    }

    @GetMapping("")
    public User read(String id) {
        return userService.read(id);
    }

    @PutMapping("")
    public User update(String id, String name) {
        return userService.update(id, name);
    }

    @DeleteMapping("")
    public void delete(String id) {
        userService.delete(id);
    }
}

MongodbApplication

@SpringBootApplication
@EnableMongoRepositories // MongoRepository 사용하기 위함
public class MongodbApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongodbApplication.class, args);
    }
}

application.yml

  • 위에서 복사한 MongoDB Atlas 접속 경로를 설정 파일에 사용합니다.
spring:
  data:
    mongodb:
      uri: mongodb+srv://<username>:<password>@<cluster>.*.mongodb.net/<database>?retryWrites=true&w=majority

문제 상황

  • 하지만 이렇게 실행하게 되면 아래 이미지와 같이 DB 경로를 찾지 못하는 에러가 발생합니다.
  • 이러한 이유는 DataSourceAutoConfiguration class 를 디버그 해보면 어느 정도 유추해볼 수 있습니다. Application 실행 시 DataSourceAutoConfiguration class 를 실행하게 되고 이 안에 있는 DataSourceProperties class 에서 문제가 발생합니다.

  • @ConfigurationProperties 의 prefix 로 "spring.datasource" 가 설정되어 있습니다. MongoDB 의 접속 설정은 "spring.data" 이므로 안되는 것이 당연해 보입니다. 더군다나 embeddedDatabase 연결도 없고 대체 driveClassName 또한 없으니 빈을 생성하는 과정에서 DataSourceBeanCreationException 이 발생하게 되고 이로 인해 Application 로드 자체가 실패하게 됩니다.

해결 방법

  • application.yml 의 설정만 있으면 application 단과 mongoDB 접속이 가능하므로 DataSourceAutoConfiguration 자체를 bean 생성 과정에서 제외시킵니다.
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableMongoRepositories // MongoRepository 사용하기 위함
public class MongodbApplication {
    public static void main(String[] args) {
        SpringApplication.run(MongodbApplication.class, args);
    }
}
  • 실행하면 아래와 같이 MongoClient 가 접속 정보를 생성하며 정상적으로 동작하는 것을 볼 수 있습니다. 저는 클러스터 레플리카를 만들어 3개가 모니터링 된다고 출력됩니다.


2. MongoConfig 를 구성하여 MongoTemplate 을 사용하는 방법

  • 이 방법에서는 User 와 UserController 는 방법1과 같지만 UserRepository 가 필요하지 않습니다.

MongoConfig

  • AbstractMongoClientConfiguration 추상 클래스를 상속받아 아래와 같이 내용을 채워넣습니다.
@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {

    @Value("${spring.data.mongodb.uri}")
    private String uri;

    @Value("${spring.data.mongodb.database}")
    private String databaseName;

    @Override
    protected String getDatabaseName() {
        return databaseName;
    }

    @Override
    public MongoClient mongoClient() {
        ConnectionString connectionString = new ConnectionString(uri);

        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
                .applyConnectionString(connectionString)
                .build();

        return MongoClients.create(mongoClientSettings);
    }

    @Bean
    public MongoTemplate mongoTemplate() {
        return new MongoTemplate(new SimpleMongoClientDatabaseFactory(mongoClient(), getDatabaseName()));
    }
}

UserService

  • 같은 CRUD 기능이지만 MongoDB Query 를 사용하는 MongoTemplate 은 구현이 조금 달라집니다.
  • 필요한 조건문을 Query 객체로 만들어 사용합니다.
@RequiredArgsConstructor
@Service
public class UserService {
    private final MongoTemplate mongoTemplate;

    public String create(String name) {
        User user = User.builder()
                .name(name)
                .build();

        return mongoTemplate.insert(user, "user").getId();
    }

    public User read(String id) {
        Query query = new Query(Criteria.where("id").is(id));

        return mongoTemplate.findOne(query, User.class, "user");
    }

    public User update(String id, String name) {
        Query query = new Query(Criteria.where("id").is(id));
        Update update = new Update().set("name", name);

        return mongoTemplate.findAndModify(query, update, User.class, "user");
    }

    public void delete(String id) {
        Query query = new Query(Criteria.where("id").is(id));

        mongoTemplate.remove(query, User.class, "user");
    }
}

실행 예시

  • IntelliJ 에서 제공하는 HTTP 서비스를 사용해보겠습니다.

Create

  • id 를 String 타입으로 설정하면 MySQL 의 GeneratedValue 처럼 id 를 기본으로 생성합니다.


Read


Update


Delete

  • 삭제 후 조회 시 응답 객체가 없는 것으로 보아 삭제 또한 잘 된 것 같습니다.


후기

MongoDB 가이드를 보고 똑같이 따라했지만 DB Driver 를 찾지 못한다는 에러가 계속 발생했고 stack overflow 검색 결과 같은 문제에서 DataSourceAutoConfiguration 을 제외하라는 답변을 발견했고 해결은 되었지만 왜 이렇게 해야만 하는지 궁금하여 이번 기회에 디버깅했습니다. 확실히 Spring 에서 제공하는 코드들을 한 줄씩 체크하며 따라가보니 코드의 흐름과 데이터베이스에 연결하는 원리를 이해하는데 도움이 된 것 같습니다. 디버깅을 자주 하는 습관을 들여야겠습니다.


참고 자료

https://stackoverflow.com/questions/51221777/failed-to-configure-a-datasource-url-attribute-is-not-specified-and-no-embedd

전체 코드

https://github.com/SudalKing/MongoDB

post-custom-banner

0개의 댓글