使用 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 上找到。