一、概述
使用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 评论