本文实践MongoDB多数据源连接,目前服务器版本分别为4及3.2,所以需要兼容这两种版本,在选择依赖包时需特别注意MongoDB版本
1. 依赖引入
mongodb与java驱动版本之间的支持关系如图所示,所以选择好版本非常关键,我之前就是因为版本问题各种报错
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb:3.0.3'
implementation 'org.mongodb:mongodb-driver-sync:4.0.6'
implementation 'org.mongodb:mongodb-driver-core:4.0.6'
implementation 'org.mongodb:bson:4.0.6'
2. yml配置
这里的配置主要是后面 @ConfigurationProperties(prefix = “spring.data.mongodb.secondary”)用到,如果有第三个数据源同理设置
spring:
data:
mongodb:
primary:
uri: mongodb://user:password@192.168.0.1:27017/sfxs?authSource=admin&authMechanism=SCRAM-SHA-1
secondary:
uri: mongodb://user:password@192.168.0.2:27017/sfxs?authSource=admin&authMechanism=SCRAM-SHA-1
3. 两种操作方式对比
Spring结合MongoDB有两种操作方式:MongoDB Template 和 JPA。
在操作 MongoDB 数据库时,各有优缺点:
对比项 | MongoDB Template | JPA |
---|---|---|
优点 | (1)更贴近 MongoDB 原生 API,可以充分利用 MongoDB 的所有功能 (2)在进行复杂的查询、聚合等操作时,更灵活和高效 (3)可以直接使用 MongoDB 的查询语言编写查询语句 | (1)可以复用 JPA 的编程模型和工具,降低学习成本 (2)与其他 JPA 兼容的数据库无缝切换,提高了应用的移植性 (3)提供了标准化的编程接口,降低了数据访问层的复杂度 |
缺点 | (1)需要编写更多的底层代码,开发效率较低 (2)需要对 MongoDB 的数据模型和查询语言有较深的了解 (3)不能与其他 JPA 兼容的数据库无缝切换 | (1)可能无法充分利用 MongoDB 的全部功能,功能受限 (2)在进行复杂的查询、聚合等操作时,性能可能较差 (3)需要额外的配置和映射,增加了开发和维护的复杂度 |
总的来说,MongoDB Template 更适合需要充分利用 MongoDB 特性的应用程序,而 JPA 则更适合需要跨数据库支持或已经基于 JPA 进行开发的项目。具体选择哪种方式,需要结合项目的实际需求和技术栈进行权衡
4. 配置类编写
咱们采用mongoTemplate语法,主要因为以下几点:
- 简单易用: mongoTemplate 提供了一系列基于 MongoDB Java Driver 的简单 CRUD 操作方法,使用起来非常方便。
- 支持模板化操作: mongoTemplate 提供了各种模板方法,如 find、insert、update 等,开发者无需直接与 MongoDB Java Driver 交互,提高了开发效率。
- 支持批量操作: mongoTemplate 支持一次性执行多个数据库操作,如批量插入、更新、删除等,提高了性能。
- 数据转换支持: mongoTemplate 可以自动将 POJO 转换为 MongoDB 文档,并将查询结果自动映射回 POJO,降低了开发人员的工作量
- 后续需要复杂的聚合操作,JPA无法满足
/**
* 默认MONGO数据源配置
*
* 默认的第一个数据源,注入时,直接
* @Autowired
* private MongoTemplate mongoTemplate;
*/
@Configuration
@EnableMongoRepositories
public class DefaultMongoTemplateConf {
private final MongoProperties mongoProperties;
public DefaultMongoTemplateConf(@Qualifier("mongoProperties") MongoProperties mongoProperties) {
this.mongoProperties = mongoProperties;
}
@Bean
@Primary
public MongoTemplate mongoTemplate() {
MongoTemplate mongoTemplate=new MongoTemplate(mongoDatabaseFactory(mongoProperties));
MappingMongoConverter mongoMapping = (MappingMongoConverter) mongoTemplate.getConverter();
mongoMapping.afterPropertiesSet();
return mongoTemplate;
}
@Bean(name = "oneMongoFactory")
@Primary
public MongoDatabaseFactory mongoDatabaseFactory(MongoProperties mongoProperties) {
return new SimpleMongoClientDatabaseFactory(mongoProperties.getUri());
}
}
@Configuration
public class MongoConfiguration {
@Bean(name = "mongoProperties")
@Primary
@ConfigurationProperties(prefix = "spring.data.mongodb.primary")
public MongoProperties masterMongoProperties() {
return new MongoProperties();
}
@Bean(name = "secondaryMongoProperties")
@ConfigurationProperties(prefix = "spring.data.mongodb.secondary")
public MongoProperties secondaryMongoProperties() {
return new MongoProperties();
}
}
/**
* 第二个MONGODB数据配置
*/
@Configuration
@EnableMongoRepositories(mongoTemplateRef = SecondaryMongoTemplateConf.MONGO_TEMPLATE)
public class SecondaryMongoTemplateConf {
public static final String MONGO_TEMPLATE = "secondaryMongoTemplate";
private final MongoProperties mongoProperties;
public SecondaryMongoTemplateConf(@Qualifier("secondaryMongoProperties") MongoProperties mongoProperties) {
this.mongoProperties = mongoProperties;
}
@Bean(name = SecondaryMongoTemplateConf.MONGO_TEMPLATE)
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoDatabaseFactory(mongoProperties));
}
@Bean(name = "secondaryMongoFactory")
public MongoDatabaseFactory mongoDatabaseFactory(MongoProperties mongoProperties) {
return new SimpleMongoClientDatabaseFactory(mongoProperties.getUri());
}
}
5. 测试类编写
在测试类中,我注入了两种不同数据源,分别查询对应Township信息
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DidataCloudApplication.class)
public class DidataTests {
@Autowired
private MongoTemplate mongoTemplate;
@Resource(name = SecondaryMongoTemplateConf.MONGO_TEMPLATE)
private MongoTemplate mongoTemplate2;
@Test
public void mongo() {
Query query = new Query(Criteria.where("province_name").is("上海市"));
Township result = mongoTemplate.findOne(query, Township.class, "township");
Assert.assertNotNull(result);
Query query1 = new Query(Criteria.where("province_name").is("上海市"));
Township result1 = mongoTemplate2.findOne(query1, Township.class, "township");
Assert.assertNotNull(result1);
}
}
6. 效果验证
运行test, 测试通过
欢迎关注公众号算法小生,言简意赅干货满满~