1. 개요

Spring Data MongoDB를 사용하여 MongoClient 를 생성하여 데이터베이스에 대한 작업을 수행할 수 있습니다. 그러나 경우에 따라 애플리케이션에서 여러 데이터베이스를 사용해야 할 수도 있습니다.

이 사용방법(예제)에서는 MongoDB에 대한 여러 연결을 만듭니다. 또한 이 시나리오를 모방하기 위해 몇 가지 Spring Boot 테스트를 추가할 것입니다.

2. Spring Data MongoDB를 사용한 다중 데이터베이스 애플리케이션

MongoDB 를 사용할 때 데이터에 액세스하기 위해 MongoTemplate 을 생성합니다 . 따라서 다양한 데이터베이스에 연결하기 위해 여러 템플릿을 만들 수 있습니다.

그러나 Spring이 고유한 bean을 찾지 못하기 때문에 NoUniqueBeanDefinitionException 을 얻을 수 있습니다 .

이를 염두에 두고 Spring Boot 구성을 빌드하는 방법을 살펴보겠습니다.

2.1. 의존성 설정

pom.xml 에 의존성을 추가하여 시작하겠습니다 . 먼저 스프링 부트 스타터 가 필요합니다 .

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.4</version>
    <relativePath />
</parent>

그런 다음 웹 스타터데이터 MongoDB 에 대한 의존성이 필요합니다 .

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

마찬가지로 Gradle을 사용하는 경우 build.gradle 에 다음을 추가합니다.

plugins {
    id 'org.springframework.boot' version '2.6.4'
}
compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
compile 'org.springframework.boot:spring-boot-starter-web'

대안으로 Spring Initializer 를 사용할 수 있습니다 .

2.2. 모델

먼저 모델을 추가해 보겠습니다. 서로 다른 두 데이터베이스에서 사용할 두 개의 문서를 만듭니다.

예를 들어 사용자 문서를 만듭니다.

@Document(collection = "user")
public class User {

    @MongoId
    private ObjectId id;

    private String name;

    private String surname;
    private String email;

    private int age;

    // getters and setters
}

그런 다음 계정 문서 도 추가해 보겠습니다 .

@Document(collection = "account")
public class Account {

    @MongoId
    private ObjectId id;

    private String userEmail;

    private String nickName;

    private String accountDomain;

    private String password;

    // getters and setters
}

2.3. 저장소

그런 다음 일부 Spring Data 메서드를 사용하여 각 모델 클래스에 대한 리포지토리를 만듭니다.

먼저 UserRepository 를 추가해 보겠습니다 .

@Repository
public interface UserRepository extends MongoRepository<User, String> {

    User findByEmail(String email);
}

다음으로 AccountRepository 를 추가합니다 .

@Repository
public interface AccountRepository extends MongoRepository<Account, String> {

    Account findByAccountDomain(String account);
}

2.4. 연결 속성

사용 중인 여러 데이터베이스의 속성을 정의해 보겠습니다.

mongodb.primary.host=localhost
mongodb.primary.database=db1
mongodb.primary.authenticationDatabase=admin
mongodb.primary.username=user1
mongodb.primary.password=password
mongodb.primary.port=27017

mongodb.secondary.host=localhost
mongodb.secondary.database=db2
mongodb.secondary.authenticationDatabase=admin
mongodb.secondary.username=user2
mongodb.secondary.password=password
mongodb.secondary.port=27017

인증에 사용할 특정 DB에 대한 속성이 있다는 점은 주목할 가치가 있습니다.

2.5. 기본 구성

이제 구성이 필요합니다. 우리는 각 데이터베이스에 대해 하나씩 만들 것입니다.

UserRepository 에 사용 중인 기본 클래스 정의를 살펴보겠습니다 .

@Configuration
@EnableMongoRepositories(basePackageClasses = UserRepository.class, mongoTemplateRef = "primaryMongoTemplate")
@EnableConfigurationProperties
public class PrimaryConfig {
    // beans
}

시연을 위해 모든 빈과 어노테이션을 분석해 보겠습니다.

먼저 MongoProperties 를 사용하여 속성을 검색하고 설정합니다 . 이 방법으로 모든 속성을 빈에 직접 매핑합니다.

@Bean(name = "primaryProperties")
@ConfigurationProperties(prefix = "mongodb.primary")
@Primary
public MongoProperties primaryProperties() {
    return new MongoProperties();
}

여러 사용자에게 액세스 권한을 부여하기 위해 MongoCredential  과 함께 MongoDB 인증 메커니즘 을 사용합니다 . 인증 데이터베이스( 이 경우 admin )를 추가하여 자격 증명 개체를 구성합니다.

@Bean(name = "primaryMongoClient")
public MongoClient mongoClient(@Qualifier("primaryProperties") MongoProperties mongoProperties) {

    MongoCredential credential = MongoCredential
      .createCredential(mongoProperties.getUsername(), mongoProperties.getAuthenticationDatabase(), mongoProperties.getPassword());

    return MongoClients.create(MongoClientSettings.builder()
      .applyToClusterSettings(builder -> builder
        .hosts(singletonList(new ServerAddress(mongoProperties.getHost(), mongoProperties.getPort()))))
      .credential(credential)
      .build());
}

최신 릴리스에서 제안한 대로 연결 문자열에서 MongoTemplate 을 만드는 대신 SimpleMongoClientDatabaseFactory 를 사용하고 있습니다.

@Primary
@Bean(name = "primaryMongoDBFactory")
public MongoDatabaseFactory mongoDatabaseFactory(
  @Qualifier("primaryMongoClient") MongoClient mongoClient, 
  @Qualifier("primaryProperties") MongoProperties mongoProperties) {
    return new SimpleMongoClientDatabaseFactory(mongoClient, mongoProperties.getDatabase());
}

더 많은 데이터베이스 구성을 추가할 것이므로 여기에서 빈이 @Primary 여야 합니다 . 그렇지 않으면 앞서 논의한 고유성 제약 조건에 빠지게 됩니다.

여러 EntityManager 를 매핑할 때 JPA에서도 동일한 작업을 수행합니다 . 마찬가지로 @EnableMongoRepositories에 Mongotemplate 에 대한 참조가 필요합니다 .

@EnableMongoRepositories(basePackageClasses = UserRepository.class, mongoTemplateRef = "primaryMongoTemplate")

2.6. 보조 구성

마지막으로 재확인을 위해 두 번째 데이터베이스 구성을 살펴보겠습니다.

@Configuration
@EnableMongoRepositories(basePackageClasses = AccountRepository.class, mongoTemplateRef = "secondaryMongoTemplate")
@EnableConfigurationProperties
public class SecondaryConfig {

    @Bean(name = "secondaryProperties")
    @ConfigurationProperties(prefix = "mongodb.secondary")
    public MongoProperties secondaryProperties() {
        return new MongoProperties();
    }

    @Bean(name = "secondaryMongoClient")
    public MongoClient mongoClient(@Qualifier("secondaryProperties") MongoProperties mongoProperties) {

        MongoCredential credential = MongoCredential
          .createCredential(mongoProperties.getUsername(), mongoProperties.getAuthenticationDatabase(), mongoProperties.getPassword());

        return MongoClients.create(MongoClientSettings.builder()
          .applyToClusterSettings(builder -> builder
            .hosts(singletonList(new ServerAddress(mongoProperties.getHost(), mongodProperties.getPort()))))
          .credential(credential)
          .build());
    }

    @Bean(name = "secondaryMongoDBFactory")
    public MongoDatabaseFactory mongoDatabaseFactory(
      @Qualifier("secondaryMongoClient") MongoClient mongoClient, 
      @Qualifier("secondaryProperties") MongoProperties mongoProperties) {
        return new SimpleMongoClientDatabaseFactory(mongoClient, mongoProperties.getDatabase());
    }

    @Bean(name = "secondaryMongoTemplate")
    public MongoTemplate mongoTemplate(@Qualifier("secondaryMongoDBFactory") MongoDatabaseFactory mongoDatabaseFactory) {
        return new MongoTemplate(mongoDatabaseFactory);
    }
}

이 경우 AccountRepository 또는 동일한 패키지에 속하는 모든 클래스 를 참조합니다 .

3. 테스트

MongoDB 인스턴스에 대해 애플리케이션을 테스트합니다. Docker와 함께 MongoDB를 사용할 수 있습니다 .

3.1. MongoDB 컨테이너 시작

Docker Compose 를 사용하여 MongoDB 컨테이너를 실행해 보겠습니다 . YAML 템플릿을 살펴보겠습니다.

services:
  mongo:
    hostname: localhost
    container_name: 'mongo'
    image: 'mongo:latest'
    expose:
      - 27017
    ports:
      - 27017:27017
    environment:
      - MONGO_INITDB_DATABASE=admin
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=admin
    volumes:
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js

인증을 받으려면 루트 사용자로 초기화해야 합니다. 더 많은 사용자로 데이터베이스를 채우기 위해 JavaScript 초기화 파일에 바인드 마운트 를 추가하고 있습니다.

db.createUser(
    {
        user: "user1",
        pwd: "password",
        roles: [ { role: "readWrite", db: "db1" } ]
    }
)

db.createUser(
    {
        user: "user2",
        pwd: "password",
        roles: [ { role: "readWrite", db: "db2" } ]
    }
)

컨테이너를 실행해 보겠습니다.

docker-compose up -d

컨테이너가 시작되면 mongo-init.js 파일에 대한 볼륨을 생성하고 컨테이너의 진입점에 복사합니다.

3.2. 스프링 부트 테스트

몇 가지 기본 Spring Boot 테스트 에서 모두 함께 래핑해 보겠습니다 .

@SpringBootTest(classes = { SpringBootMultipeDbApplication.class })
@TestPropertySource("/multipledb/multidb.properties")
public class MultipleDbUnitTest {

    // set up

    @Test
    void whenFindUserByEmail_thenNameOk() {
        assertEquals("name", userRepository.findByEmail("user@gmail.com")
          .getName());
    }

    @Test
    void whenFindAccountByDomain_thenNickNameOk() {
        assertEquals("nickname", accountRepository.findByAccountDomain("account@jira.baeldung.com")
          .getNickName());
    }
}

주로 데이터베이스에 대한 연결을 설정하고 인증을 받기를 원합니다. 그렇지 않으면 데이터베이스가 채워지지 않았거나 MongoDb 인스턴스가 시작되지 않았을 수 있습니다.

이러한 경우 DB 컨테이너의 로그를 볼 수 있습니다. 예를 들면 다음과 같습니다.

docker logs 30725c8635d4

초기 JavaScript는 컨테이너가 처음 실행될 때만 실행된다는 점은 주목할 가치가 있습니다. 따라서 다른 스크립트로 실행해야 하는 경우 볼륨을 삭제해야 할 수 있습니다.

docker-compose down -v

4. 결론

이 기사에서는 Spring Data MongoDB로 다중 연결을 생성하는 방법을 살펴보았습니다. 인증을 받기 위해 자격 증명을 추가하는 방법을 살펴보았습니다. 가장 중요한 것은 구성을 생성하는 방법을 보았으며 그 중 하나는 기본 빈과 함께 구성되어야 합니다. 마지막으로 Docker 및 Spring Boot 테스트를 사용하여 실행 중인 MongoDB 인스턴스에 대한 몇 가지 테스트 사례를 추가했습니다.

항상 그렇듯이 기사의 전체 코드는 GitHub 에서 사용할 수 있습니다 .

Persistence footer banner