SpringBoot整合MongoDB全流程实践指南与优化

环境准备与依赖配置

在IDEA中创建新Spring Boot项目时,建议选择2.7.x或3.x版本。打开pom.xml文件添加核心依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

针对多环境配置,在application.yml中设置:

spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
      database: techblog
      authentication-database: admin 
      username: admin
      password: securepass

建议使用Testcontainers进行集成测试:

@Testcontainers
@SpringBootTest
class MongoIntegrationTest {
    @Container
    static MongoDBContainer mongoDB = new MongoDBContainer("mongo:6.0");
    
    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.mongodb.uri", mongoDB::getReplicaSetUrl);
    }
}

实体映射最佳实践

使用Morphia风格的注解定义领域模型:

@Document(collection = "articles")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Article {
    @Id
    private String id;
    @Indexed(unique = true)
    private String slug;
    @Field("content")
    private String body;
    private List<String> tags;
    @CreatedDate
    private LocalDateTime createTime;
    @Version
    private Long version;
}

注意处理BSON的特殊类型:

@Field(targetType = BsonType.DATE_TIME)
private Instant publishDate;

数据访问层实现

继承MongoRepository接口:

public interface ArticleRepository extends MongoRepository<Article, String> {
    
    @Query("{ 'tags': { $in: ?0 } }")
    List<Article> findByTags(List<String> tags);
    
    @Aggregation(pipeline = {
        "{ $match: { status: 'PUBLISHED' } }",
        "{ $group: { _id: '$category', total: { $sum: 1 } } }"
    })
    List<CategoryCount> countByCategory();
}

使用MongoTemplate进行复杂操作:

public class CustomRepoImpl implements CustomRepo {
    
    @Autowired
    private MongoTemplate mongo;
    
    public List<Article> search(String keyword) {
        TextCriteria criteria = TextCriteria.forDefaultLanguage()
            .matchingAny(keyword);
        
        Query query = TextQuery.queryText(criteria)
            .sortByScore()
            .with(Sort.by("publishDate").descending());
        
        return mongo.find(query, Article.class);
    }
}

事务管理与性能优化

在配置类中启用MongoDB事务:

@Configuration
@EnableMongoAuditing
@EnableMongoRepositories(basePackages = "com.example.repository")
public class MongoConfig extends AbstractMongoClientConfiguration {
    
    @Override
    protected boolean autoIndexCreation() {
        return true;
    }
}

使用声明式事务:

@Transactional
public void updateArticleWithComments(String articleId, Comment comment) {
    articleRepo.findById(articleId).ifPresent(article -> {
        comment.setArticleId(articleId);
        commentRepo.save(comment);
        article.setCommentCount(article.getCommentCount() + 1);
    });
}

性能优化策略:

  1. 创建复合索引
mongoTemplate.indexOps(Article.class)
    .ensureIndex(new Index().on("category", Sort.Direction.ASC)
    .on("publishDate", Sort.Direction.DESC));
  1. 使用投影减少数据传输
Query query = new Query()
    .addCriteria(Criteria.where("status").is("PUBLISHED"))
    .fields().include("title").include("createTime");
  1. 批量写入优化
List<BulkWriteOperation> bulkOps = articles.stream()
    .map(doc -> new UpdateOneModel<>(
        Filters.eq("_id", doc.getId()),
        Updates.combine(
            Updates.set("title", doc.getTitle()),
            Updates.set("content", doc.getContent())
        ),
        new UpdateOptions().upsert(true)
    )).collect(Collectors.toList());

mongoTemplate.getCollection("articles").bulkWrite(bulkOps);

聚合查询实战

构建复杂分析查询:

Aggregation agg = Aggregation.newAggregation(
    match(Criteria.where("status").is("PUBLISHED")),
    group("category")
        .count().as("total")
        .avg("readTime").as("avgReadTime"),
    project("total","avgReadTime")
        .and("category").previousOperation(),
    sort(Sort.Direction.DESC, "total")
);

AggregationResults<CategoryStats> results = mongoTemplate
    .aggregate(agg, "articles", CategoryStats.class);

时间序列数据处理:

@TimeSeries(
    timeField = "timestamp",
    metaField = "metadata",
    granularity = TimeSeriesGranularity.HOURS
)
public class Metric {
    // 时间序列字段定义
}

监控与诊断配置

集成Micrometer监控:

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,mongodb
  metrics:
    tags:
      application: ${spring.application.name}

配置慢查询日志:

db.setProfilingLevel(1, { slowms: 100 })
db.system.profile.find().sort({ ts: -1 }).limit(10)

数据迁移策略

使用MongoDump进行备份:

mongodump --uri="mongodb://user:pass@host:27017/dbname" --gzip --archive=/backup/202308.archive

实施版本化迁移:

@ChangeSet(order = "001", id = "create_articles", author = "dev")
public void createCollection(MongoDatabase db) {
    db.createCollection("articles", new CreateCollectionOptions()
        .validationOptions(new ValidationOptions()
            .validator(Filters.exists("slug"))
        )
    );
}
正文到此结束
评论插件初始化中...
Loading...