使用 Spring Data MongoDB 連接到多個數據庫
一、概述
使用 Spring Data MongoDB,我們可以創建一個MongoClient
來對數據庫進行操作。但是,有時,我們可能需要在應用程序中使用多個數據庫。
在本教程中,我們將創建到 MongoDB 的多個連接。我們還將添加一些 Spring Boot 測試來模擬這個場景。
2. Spring Data MongoDB 的多數據庫應用
使用 MongoDB 時,我們創建一個MongoTemplate
來訪問數據。因此,我們可以創建多個模板來連接各種數據庫。
但是,我們可以得到NoUniqueBeanDefinitionException
,因為 Spring 沒有找到唯一的 bean。
考慮到這一點,讓我們看看如何構建 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 實例添加了一些測試用例,
與往常一樣,本文的整個代碼都可以在 GitHub 上找到。