SpringBoot整合MongoDB全流程实践指南
- 发布时间:2025-03-16 17:56:41
- 本文热度:浏览 31 赞 0 评论 0
- 文章标签: SpringBoot MongoDB NoSQL
- 全文共1字,阅读约需1分钟
环境准备与基础集成
1.1 创建Spring Boot项目
使用Spring Initializr创建项目时,勾选以下依赖:
- Spring Data MongoDB
- Lombok(推荐)
- Spring Web(可选)
curl https://start.spring.io/starter.zip -d dependencies=web,data-mongodb,lombok -d type=gradle-project -o mongo-demo.zip
1.2 配置连接参数
在application.yml中配置集群连接:
spring:
data:
mongodb:
uri: mongodb+srv://<username>:<password>@cluster0.abcd.mongodb.net/<database>?retryWrites=true&w=majority
auto-index-creation: true
生产环境建议使用加密配置:
@Configuration
public class MongoConfig {
@Value("${encrypted.mongo.uri}")
private String encryptedUri;
@Bean
public MongoClient mongoClient() {
String decryptedUri = DecryptUtil.decrypt(encryptedUri);
return MongoClients.create(decryptedUri);
}
}
数据建模与Repository
2.1 实体类注解深度解析
@Document(collection = "products", collation = "en_US")
@CompoundIndex(def = "{'name': 1, 'category': -1}", name = "name_category_idx")
public class Product {
@Id
private String id;
@Indexed(unique = true, direction = IndexDirection.DESCENDING)
private String sku;
@Field("product_name")
@TextIndexed(weight = 2)
private String name;
@Transient
private BigDecimal temporaryPrice;
@CreatedDate
private Instant createdAt;
@Version
private Long version;
}
2.2 自定义Repository实现
扩展基础Repository接口:
public interface CustomProductRepository {
List<Product> findRecentlyUpdated(int days);
}
public class ProductRepositoryImpl implements CustomProductRepository {
private final MongoTemplate mongoTemplate;
public List<Product> findRecentlyUpdated(int days) {
Criteria criteria = Criteria.where("lastModifiedDate")
.gt(LocalDateTime.now().minusDays(days));
Query query = new Query(criteria);
return mongoTemplate.find(query, Product.class);
}
}
复杂查询与聚合操作
3.1 多条件动态查询
使用QueryDSL实现类型安全的查询:
public interface ProductRepository extends
MongoRepository<Product, String>, QuerydslPredicateExecutor<Product> {}
// 使用示例
BooleanBuilder predicate = new BooleanBuilder();
QProduct product = QProduct.product;
if (StringUtils.hasText(name)) {
predicate.and(product.name.containsIgnoreCase(name));
}
if (minPrice != null) {
predicate.and(product.price.goe(minPrice));
}
Iterable<Product> result = repository.findAll(predicate);
3.2 聚合管道实战
统计各分类商品数量及平均价格:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group("category")
.count().as("totalProducts")
.avg("price").as("avgPrice"),
Aggregation.sort(Sort.Direction.DESC, "avgPrice"),
Aggregation.limit(10)
);
AggregationResults<CategoryStats> results = mongoTemplate.aggregate(
aggregation, "products", CategoryStats.class);
事务管理与性能优化
4.1 多文档事务处理
@Transactional
public void transferInventory(String fromSku, String toSku, int quantity) {
Product source = productRepo.findBySku(fromSku)
.orElseThrow(() -> new ProductNotFoundException(fromSku));
Product target = productRepo.findBySku(toSku)
.orElseThrow(() -> new ProductNotFoundException(toSku));
if (source.getStock() < quantity) {
throw new InsufficientStockException();
}
source.setStock(source.getStock() - quantity);
target.setStock(target.getStock() + quantity);
productRepo.saveAll(List.of(source, target));
}
4.2 性能优化策略
- 索引优化工具使用:
mongoTemplate.indexOps(Product.class).getIndexInfo()
.forEach(index -> log.info("Index details: {}", index));
- 批量写入优化:
BulkOperations bulkOps = mongoTemplate.bulkOps(BulkMode.ORDERED, Product.class);
products.forEach(product ->
bulkOps.insert(documentFactory.createBulkItem(product)));
BulkWriteResult result = bulkOps.execute();
监控与调试
5.1 集成Micrometer监控
配置指标收集:
management:
metrics:
enable:
mongodb: true
endpoints:
web:
exposure:
include: health,metrics,mongodb
自定义指标采集:
@Bean
MongoMetricsCommandListener mongoMetricsCommandListener(MeterRegistry registry) {
return new MongoMetricsCommandListener(registry);
}
5.2 查询性能分析
启用慢查询日志:
@Bean
public MongoClientSettings mongoClientSettings() {
return MongoClientSettings.builder()
.applyToClusterSettings(builder ->
builder.serverSelectionTimeout(5, TimeUnit.SECONDS))
.applyToConnectionPoolSettings(builder ->
builder.maxWaitTime(2, TimeUnit.SECONDS))
.addCommandListener(new SlowQueryListener(100))
.build();
}
测试策略
6.1 集成测试配置
使用Testcontainers进行真实数据库测试:
@Testcontainers
@DataMongoTest
@Import(TestConfig.class)
class ProductRepositoryTest {
@Container
static MongoDBContainer mongoDB = new MongoDBContainer("mongo:5.0");
@DynamicPropertySource
static void setProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", mongoDB::getReplicaSetUrl);
}
@Test
void shouldSaveAndRetrieveProduct() {
Product product = new Product("Test SKU", "Test Product");
repository.save(product);
assertThat(repository.findBySku("Test SKU")).isPresent();
}
}
6.2 单元测试Mock技巧
使用Mockito进行Repository层测试:
@ExtendWith(MockitoExtension.class)
class ProductServiceTest {
@Mock
private ProductRepository repository;
@InjectMocks
private ProductService service;
@Test
void shouldHandleEmptyResult() {
when(repository.findBySku(anyString())).thenReturn(Optional.empty());
assertThrows(ProductNotFoundException.class,
() -> service.getProductDetails("INVALID_SKU"));
}
}
高级特性集成
7.1 Change Stream监听
实现实时数据变更监听:
@Configuration
public class ChangeStreamConfig {
@Bean
public MessageListenerContainer messageListenerContainer(
MongoTemplate mongoTemplate) {
return new DefaultMessageListenerContainer(mongoTemplate) {
@Override
public void start() {
super.start();
ChangeStreamRequest<Product> request = ChangeStreamRequest.builder()
.collection("products")
.filter(newAggregation(match(where("operationType").in("insert", "update"))))
.publishFullDocumentOnly()
.build();
this.register(request, Product.class, System.out::println);
}
};
}
}
7.2 地理位置查询
实现附近门店搜索:
@Document
public class Store {
@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
private GeoJsonPoint location;
}
public interface StoreRepository extends MongoRepository<Store, String> {
@Query("{'location': {$near: {$geometry: {type: 'Point', coordinates: ?0 }, $maxDistance: ?1}}}")
List<Store> findNearbyStores(double[] coordinates, double maxDistance);
}
生产环境最佳实践
8.1 连接池配置优化
spring:
data:
mongodb:
uri: mongodb://host1,host2,host3/db?connectTimeoutMS=3000
auto-index-creation: false # 生产环境应关闭
client:
min-pool-size: 5
max-pool-size: 50
max-idle-time: 180000
8.2 版本迁移策略
使用Flyway进行数据迁移:
@Configuration
public class MongoMigrationConfig {
@Bean
public FlywayMigrationStrategy flywayMigrationStrategy() {
return flyway -> {
flyway.setLocations("classpath:db/migration/mongo");
flyway.migrate();
};
}
}
典型问题排查
9.1 连接超时问题分析
常见错误模式及解决方案:
- 防火墙限制:检查云安全组设置
- DNS解析失败:配置/etc/hosts或使用IP直连
- 驱动版本不兼容:确保Spring Data MongoDB版本与MongoDB服务器版本匹配
9.2 索引失效场景
典型索引失效案例:
// 错误:使用$or查询导致索引失效
@Query("{ $or: [ { 'name': ?0 }, { 'description': ?0 } ] }")
List<Product> searchProducts(String keyword);
// 正确:创建复合索引
@CompoundIndex(name = "search_idx", def = "{'name': 1, 'description': 1}")
正文到此结束
相关文章
热门推荐
评论插件初始化中...