拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 使用Spring Data MongoDB 连接到多个数据库

使用Spring Data MongoDB 连接到多个数据库

白鹭 - 2022-09-08 2159 0 2

一、概述

使用Spring Data MongoDB,我们可以创建一个MongoClient来对数据库进行操作。但是,有时,我们可能需要在应用程序中使用多个数据库。

在本教程中,我们将创建到MongoDB 的多个连接。我们还将添加一些Spring Boot 测试来模拟这个场景。

2. Spring Data MongoDB 的多数据库应用

使用MongoDB 时,我们创建一个MongoTemplate来访问数据。因此,我们可以创建多个模板来连接各种数据库。

但是,我们可以得到,因为Spring 没有找到唯一的bean。NoUniqueBeanDefinitionException

考虑到这一点,让我们看看如何构建Spring Boot 配置。

2.1。依赖设置

让我们从向pom.xml.首先,我们需要一个spring boot 启动器:

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

然后,我们需要一个web starter数据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.模型

首先,让我们添加我们的模型。我们将创建两个文档,供两个不同的数据库使用。

例如,我们将创建一个User文档:

@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
 }

然后,我们还要添加一个Account文档:

@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

值得注意的是,我们有一个用于身份验证的特定数据库的属性。

2.5.主要配置

现在,我们需要我们的配置。我们将为每个数据库制作一个。

让我们看一下用于UserRepository的主要类定义:

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

为了演示,让我们分解所有的bean 和注释。

首先,我们将使用[MongoProperties](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/mongo/MongoProperties.html) .这样,我们直接将所有属性映射到一个bean:

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

为了向多个用户授予访问权限,我们使用带有[MongoCredential .](https://mongodb.github.io/mongo-java-driver/3.6/javadoc/com/mongodb/MongoCredential.html)的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());
 }

正如最新版本所建议的,我们使用[SimpleMongoClientDatabaseFactory](https://docs.spring.io/spring-data/data-mongo/docs/4.0.x/reference/html/#mongo.mongo-db-factory)而不是从连接字符串创建MongoTemplate

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

我们需要我们的bean 在这里是@Primary,因为我们将添加更多的数据库配置否则,我们将落入我们之前讨论过的唯一性约束。

当我们映射多个EntityManager时,我们对JPA 执行相同的操作。同样,我们需要在Mongotemplate中引用@EnableMongoRepositories:

@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 实例测试应用程序。我们可以将MongoDB 与Docker 一起使用。

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

如果我们想要进行身份验证,我们需要使用root 用户进行初始化。为了用更多用户填充数据库,我们将绑定挂载添加到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("[email protected]")
 .getName());
 }
 @Test
 void whenFindAccountByDomain_thenNickNameOk() {
 assertEquals("nickname", accountRepository.findByAccountDomain("[email protected]")
 .getNickName());
 }
 }

首先,我们要为数据库建立连接并获得身份验证。如果我们不这样做,我们可能没有填充数据库或没有启动MongoDb 实例。

在这些情况下,我们可以查看数据库容器的日志,例如:

docker logs 30725c8635d4

值得注意的是,初始JavaScript 仅在容器第一次运行时执行。因此,如果我们需要使用不同的脚本运行,我们可能需要删除卷:

docker-compose down -v

4。结论

在本文中,我们了解了如何使用Spring Data MongoDB 创建多个连接。我们看到了如何添加凭据以进行身份验证。最重要的是,我们已经了解了如何创建配置,其中之一必须是主bean。最后,我们使用Docker 和Spring Boot 测试针对正在运行的MongoDB 实例添加了一些测试用例


标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *