SpringBoot 深度集成 MongoDB 详细步骤
- 1. MongoDB 简介与 SpringBoot 集成概述
- 1.1 SpringBoot 集成 MongoDB 的优势
- 2. 环境准备与依赖配置
- 2.1 版本兼容性矩阵
- 2.2 详细依赖配置
- 2.3 详细配置说明
- 2.3.1 单节点配置
- 2.3.2 集群配置
- 3. 实体映射与集合管理
- 3.1 详细实体类注解
- 3.2 索引管理
- 4. 数据操作详解
- 4.1 Repository 接口扩展
- 4.2 MongoTemplate 高级操作
- 4.2.1 CRUD 操作
- 4.2.2 复杂查询构建
- 4.2.3 聚合操作
- 5. 高级特性与最佳实践
- 5.1 事务管理
- 5.2 变更流(Change Streams)
- 5.3 GridFS 文件存储
- 5.4 性能优化策略
- 6. 实战案例:电商平台商品管理系统
- 6.1 系统架构设计
- 6.2 核心功能实现
- 6.2.1 商品服务
- 6.2.2 商品评价服务
- 7. 测试策略
- 7.1 单元测试
- 7.2 集成测试
- 8. 常见问题与解决方案
- 8.1 连接问题排查
- 8.2 性能问题排查
- 8.3 数据一致性问题
- 9. 未来发展与扩展
- 9.1 分片集群扩展
- 9.2 时间序列集合(MongoDB 5.0+)
- 9.3 与 Atlas Search 集成
- 10. 总结
1. MongoDB 简介与 SpringBoot 集成概述
MongoDB 是一个基于分布式文件存储的开源 NoSQL 数据库系统,采用文档存储格式(BSON,类似 JSON)。与传统关系型数据库相比,MongoDB 具有以下特点:
- 无模式设计:集合中的文档可以有不同的结构
- 水平扩展:通过分片实现数据分布式存储
- 高性能:内存映射文件技术提高 I/O 效率
- 丰富的查询语言:支持丰富的查询表达式和索引类型
- 聚合框架:强大的数据分析能力
1.1 SpringBoot 集成 MongoDB 的优势
- 自动配置:SpringBoot 自动配置 MongoDB 客户端连接
- Repository 抽象:类似 JPA 的操作方式,降低学习曲线
- 对象映射:自动将 Java 对象与 MongoDB 文档相互转换
- 事务支持:支持多文档 ACID 事务(MongoDB 4.0+)
- 与 Spring 生态无缝集成:可与 Spring Data、Spring Security 等协同工作
2. 环境准备与依赖配置
2.1 版本兼容性矩阵
SpringBoot 版本 | Spring Data MongoDB 版本 | MongoDB 驱动版本 | MongoDB 服务器版本 |
---|---|---|---|
2.7.x | 3.4.x | 4.4.x | 4.4-5.0 |
3.0.x | 4.0.x | 4.8.x | 5.0-6.0 |
3.1.x | 4.1.x | 4.9.x | 6.0+ |
2.2 详细依赖配置
<!-- pom.xml -->
<dependencies><!-- SpringBoot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Data 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-data-mongodb-reactive</artifactId></dependency><!-- 工具类 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- MongoDB 嵌入式测试 --><dependency><groupId>de.flapdoodle.embed</groupId><artifactId>de.flapdoodle.embed.mongo</artifactId><scope>test</scope></dependency>
</dependencies>
2.3 详细配置说明
2.3.1 单节点配置
# application.yml
spring:data:mongodb:host: localhostport: 27017database: mydbusername: myuserpassword: mypasswordauthentication-database: admin # 认证数据库# 连接池配置auto-index-creation: truegridfs:database: mygridfs # GridFS 存储的数据库
2.3.2 集群配置
spring:data:mongodb:uri: mongodb://user:password@host1:27017,host2:27017,host3:27017/mydb?replicaSet=myReplicaSet&authSource=admin# 高级连接配置option:min-connection-per-host: 10max-connection-per-host: 100max-wait-time: 120000connect-timeout: 5000socket-timeout: 60000server-selection-timeout: 30000
3. 实体映射与集合管理
3.1 详细实体类注解
import org.springframework.data.annotation.*;
import org.springframework.data.mongodb.core.index.*;
import org.springframework.data.mongodb.core.mapping.*;@Document(collection = "products") // 指定集合名称
@CompoundIndex(def = "{'name': 1, 'category': 1}", name = "name_category_idx")
public class Product {@Idprivate String id;@Indexed(unique = true, direction = IndexDirection.ASCENDING)private String sku;@Field("product_name") // 自定义字段名@TextIndexed(weight = 2)private String name;@TextIndexedprivate String description;@Indexed(direction = IndexDirection.DESCENDING)private Double price;@Indexedprivate String category;@CreatedDateprivate Date createTime;@LastModifiedDateprivate Date updateTime;@Versionprivate Long version;@DBRefprivate List<Review> reviews;@Transient // 不持久化到数据库private Double discountPrice;// 嵌套文档private Manufacturer manufacturer;// 数组private List<String> tags;// 地理空间数据@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)private double[] location;// 省略 getter/setter
}// 嵌套文档类
public class Manufacturer {private String name;private String address;private String contact;
}// 引用文档类
@Document(collection = "reviews")
public class Review {@Idprivate String id;private String content;private Integer rating;private Date createTime;
}
3.2 索引管理
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.index.IndexInfo;@Service
public class IndexManagementService {@Autowiredprivate MongoTemplate mongoTemplate;// 创建索引public String createIndex(Class<?> entityClass, String field, IndexDirection direction) {IndexOperations indexOps = mongoTemplate.indexOps(entityClass);Index index = new Index().on(field, direction);return indexOps.ensureIndex(index);}// 创建复合索引public String createCompoundIndex(Class<?> entityClass, String... fields) {IndexOperations indexOps = mongoTemplate.indexOps(entityClass);IndexDefinition indexDef = new CompoundIndexDefinition(new Document().append(fields[0], 1).append(fields[1], 1));return indexOps.ensureIndex(indexDef);}// 创建文本索引public String createTextIndex(Class<?> entityClass, String... fields) {IndexOperations indexOps = mongoTemplate.indexOps(entityClass);IndexDefinition indexDef = new TextIndexDefinitionBuilder().onFields(fields).withDefaultLanguage("english").withLanguageOverride("language").build();return indexOps.ensureIndex(indexDef);}// 获取所有索引public List<IndexInfo> getIndexes(Class<?> entityClass) {IndexOperations indexOps = mongoTemplate.indexOps(entityClass);return indexOps.getIndexInfo();}// 删除索引public void dropIndex(Class<?> entityClass, String indexName) {IndexOperations indexOps = mongoTemplate.indexOps(entityClass);indexOps.dropIndex(indexName);}
}
4. 数据操作详解
4.1 Repository 接口扩展
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.*;public interface ProductRepository extends MongoRepository<Product, String> {// 基本查询List<Product> findByName(String name);Product findBySku(String sku);List<Product> findByPriceBetween(Double minPrice, Double maxPrice);List<Product> findByCategoryOrderByPriceDesc(String category);// 分页查询Page<Product> findByCategory(String category, Pageable pageable);// 使用 @Query 注解@Query("{'name': ?0}")List<Product> findByNameCustom(String name);@Query("{'price': {$gt: ?0, $lt: ?1}}")List<Product> findByPriceRange(Double minPrice, Double maxPrice);// 使用正则表达式List<Product> findByNameLike(String namePattern);// 使用 SpEL 表达式@Query("{'$where': 'this.price > ?0'}")List<Product> findByPriceGreaterThan(Double price);// 多条件查询List<Product> findByNameAndCategory(String name, String category);// 使用聚合@Aggregation(pipeline = {"{$match: {category: ?0}}","{$group: {_id: '$manufacturer.name', avgPrice: {$avg: '$price'}}}"})List<AveragePriceByManufacturer> averagePriceByManufacturer(String category);// 文本搜索@TextScoreList<Product> findByDescriptionContaining(String text, Pageable pageable);// 地理空间查询List<Product> findByLocationNear(Point point, Distance distance);// 使用 exists 查询List<Product> findByManufacturerExists(boolean exists);// 使用注解定义索引@Meta(maxScanDocuments = 1000)List<Product> findByTagsIn(List<String> tags);
}// 聚合结果投影接口
public interface AveragePriceByManufacturer {String getManufacturerName();Double getAvgPrice();
}
4.2 MongoTemplate 高级操作
4.2.1 CRUD 操作
@Service
public class ProductService {@Autowiredprivate MongoTemplate mongoTemplate;// 插入文档public Product saveProduct(Product product) {return mongoTemplate.save(product);}// 批量插入public List<Product> saveAllProducts(List<Product> products) {return mongoTemplate.insertAll(products);}// 查询单个文档public Product findById(String id) {return mongoTemplate.findById(id, Product.class);}// 条件查询public List<Product> findExpensiveProducts(Double minPrice) {Query query = new Query(Criteria.where("price").gt(minPrice));return mongoTemplate.find(query, Product.class);}// 更新文档public UpdateResult updateProductPrice(String id, Double newPrice) {Query query = new Query(Criteria.where("id").is(id));Update update = new Update().set("price", newPrice).currentDate("updateTime");return mongoTemplate.updateFirst(query, update, Product.class);}// 删除文档public DeleteResult deleteProduct(String id) {Query query = new Query(Criteria.where("id").is(id));return mongoTemplate.remove(query, Product.class);}
}
4.2.2 复杂查询构建
public List<Product> complexProductSearch(ProductSearchCriteria criteria) {Criteria criteriaChain = new Criteria();// 关键词查询if (StringUtils.isNotBlank(criteria.getKeyword())) {TextCriteria textCriteria = TextCriteria.forDefaultLanguage().matchingAny(criteria.getKeyword()).caseSensitive(false);criteriaChain.andOperator(textCriteria);}// 分类过滤if (CollectionUtils.isNotEmpty(criteria.getCategories())) {criteriaChain.and("category").in(criteria.getCategories());}// 价格范围if (criteria.getMinPrice() != null || criteria.getMaxPrice() != null) {Criteria priceCriteria = new Criteria("price");if (criteria.getMinPrice() != null) {priceCriteria.gte(criteria.getMinPrice());}if (criteria.getMaxPrice() != null) {priceCriteria.lte(criteria.getMaxPrice());}criteriaChain.andOperator(priceCriteria);}// 标签查询if (CollectionUtils.isNotEmpty(criteria.getTags())) {criteriaChain.and("tags").all(criteria.getTags());}// 地理位置查询if (criteria.getLatitude() != null && criteria.getLongitude() != null) {Point point = new Point(criteria.getLongitude(), criteria.getLatitude());criteriaChain.and("location").nearSphere(point).maxDistance(criteria.getDistanceInKilometers() / 111.12); // 转换为弧度}Query query = new Query(criteriaChain);// 排序if (StringUtils.isNotBlank(criteria.getSortBy())) {Sort.Direction direction = criteria.isAscending() ? Sort.Direction.ASC : Sort.Direction.DESC;query.with(Sort.by(direction, criteria.getSortBy()));}// 分页if (criteria.getPage() != null && criteria.getSize() != null) {query.with(PageRequest.of(criteria.getPage(), criteria.getSize()));}// 字段投影if (CollectionUtils.isNotEmpty(criteria.getFieldsToInclude())) {Fields fields = Fields.fields();criteria.getFieldsToInclude().forEach(fields::include);query.fields(fields);}return mongoTemplate.find(query, Product.class);
}
4.2.3 聚合操作
public List<CategoryStats> getCategoryStatistics() {Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(Criteria.where("price").gt(0)), // 过滤条件Aggregation.group("category") // 按分类分组.avg("price").as("avgPrice") // 计算平均价格.sum("price").as("totalRevenue") // 计算总收入.count().as("productCount"), // 计算产品数量Aggregation.project() // 投影.and("_id").as("category").and("avgPrice").as("avgPrice").and("totalRevenue").as("totalRevenue").and("productCount").as("productCount"),Aggregation.sort(Sort.Direction.DESC, "totalRevenue"), // 按总收入降序排序Aggregation.limit(10) // 限制返回结果数);AggregationResults<CategoryStats> results = mongoTemplate.aggregate(aggregation, "products", CategoryStats.class);return results.getMappedResults();
}// 聚合结果类
@Data
public static class CategoryStats {private String category;private Double avgPrice;private Double totalRevenue;private Long productCount;
}
5. 高级特性与最佳实践
5.1 事务管理
@Service
public class OrderService {@Autowiredprivate MongoTemplate mongoTemplate;@Autowiredprivate ProductRepository productRepository;@Transactionalpublic Order createOrder(Order order) {// 检查并扣减库存for (OrderItem item : order.getItems()) {Product product = productRepository.findById(item.getProductId()).orElseThrow(() -> new RuntimeException("Product not found"));if (product.getStock() < item.getQuantity()) {throw new RuntimeException("Insufficient stock");}product.setStock(product.getStock() - item.getQuantity());productRepository.save(product);}// 保存订单return mongoTemplate.save(order);}// 配置事务管理器@Beanpublic MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {return new MongoTransactionManager(dbFactory);}
}
5.2 变更流(Change Streams)
@Service
public class ProductChangeListener {@Autowiredprivate MongoTemplate mongoTemplate;@PostConstructpublic void watchProductChanges() {new Thread(() -> {List<Bson> pipeline = Arrays.asList(Aggregates.match(Filters.in("operationType", Arrays.asList("insert", "update", "delete"))));MongoCollection<Document> collection = mongoTemplate.getCollection("products");ChangeStreamIterable<Document> changeStream = collection.watch(pipeline).fullDocument(FullDocument.UPDATE_LOOKUP);changeStream.forEach(event -> {String operationType = event.getOperationType().getValue();Document fullDocument = event.getFullDocument();switch (operationType) {case "insert":handleInsert(fullDocument);break;case "update":handleUpdate(event.getDocumentKey(), fullDocument);break;case "delete":handleDelete(event.getDocumentKey());break;}});}).start();}private void handleInsert(Document productDoc) {System.out.println("New product added: " + productDoc.toJson());}private void handleUpdate(Bson documentKey, Document fullDocument) {System.out.println("Product updated: " + documentKey + ", new data: " + fullDocument.toJson());}private void handleDelete(Bson documentKey) {System.out.println("Product deleted: " + documentKey);}
}
5.3 GridFS 文件存储
@Service
public class FileStorageService {@Autowiredprivate GridFsTemplate gridFsTemplate;public String storeFile(InputStream inputStream, String filename, String contentType) {ObjectId fileId = gridFsTemplate.store(inputStream, filename, contentType);return fileId.toString();}public GridFSDBFile getFile(String fileId) {return gridFsTemplate.findOne(new Query(Criteria.where("_id").is(fileId)));}public void deleteFile(String fileId) {gridFsTemplate.delete(new Query(Criteria.where("_id").is(fileId)));}public List<GridFSFile> listFiles() {return gridFsTemplate.find(new Query()).into(new ArrayList<>());}
}
5.4 性能优化策略
- 索引优化:
- 为常用查询字段创建适当索引
- 使用复合索引优化多字段查询
- 定期分析查询性能并调整索引
- 查询优化:
- 使用投影只返回必要字段
- 限制返回文档数量
- 避免使用 $where 和 JavaScript 表达式
- 使用 covered queries(查询完全由索引满足)
- 批量操作:
- 使用 bulkWrite 进行批量插入/更新
- 批量操作时适当设置 ordered 参数
- 读写分离:
- 配置从节点读取
@Bean
public MongoClient mongoClient() {ConnectionString connectionString = new ConnectionString("mongodb://host1:27017,host2:27017,host3:27017/mydb?readPreference=secondaryPreferred");return MongoClients.create(connectionString);
}
- 分片集群:
- 对于大数据集,配置分片集群
- 选择合适的分片键
6. 实战案例:电商平台商品管理系统
6.1 系统架构设计
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 前端应用/API │───▶│ SpringBoot应用 │───▶│ MongoDB集群 │
└─────────────────┘ └─────────────────┘ └─────────────────┘▲ ▲ ▲│ │ │
┌──────┴───────┐ ┌─────────┴─────────┐ ┌──────┴───────┐
│ 缓存(Redis) │ │ 消息队列(Kafka) │ │ 文件存储(S3) │
└──────────────┘ └───────────────────┘ └───────────────┘
6.2 核心功能实现
6.2.1 商品服务
@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate MongoTemplate mongoTemplate;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;private static final String PRODUCT_CACHE_PREFIX = "product:";@Overridepublic Product createProduct(Product product) {// 验证SKU唯一性if (productRepository.findBySku(product.getSku()) != null) {throw new RuntimeException("SKU already exists");}// 设置创建时间product.setCreateTime(new Date());product.setUpdateTime(new Date());// 保存到数据库Product savedProduct = productRepository.save(product);// 清除相关缓存redisTemplate.delete(PRODUCT_CACHE_PREFIX + savedProduct.getId());redisTemplate.delete("products:category:" + savedProduct.getCategory());return savedProduct;}@Overridepublic Product getProductById(String id) {// 先尝试从缓存获取Product cachedProduct = (Product) redisTemplate.opsForValue().get(PRODUCT_CACHE_PREFIX + id);if (cachedProduct != null) {return cachedProduct;}// 从数据库查询Product product = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));// 存入缓存redisTemplate.opsForValue().set(PRODUCT_CACHE_PREFIX + id, product, 30, TimeUnit.MINUTES);return product;}@Overridepublic Page<Product> searchProducts(ProductSearchRequest request) {// 构建查询条件Criteria criteria = new Criteria();if (StringUtils.isNotBlank(request.getKeyword())) {criteria.orOperator(Criteria.where("name").regex(request.getKeyword(), "i"),Criteria.where("description").regex(request.getKeyword(), "i"));}if (StringUtils.isNotBlank(request.getCategory())) {criteria.and("category").is(request.getCategory());}if (request.getMinPrice() != null && request.getMaxPrice() != null) {criteria.and("price").gte(request.getMinPrice()).lte(request.getMaxPrice());}Query query = new Query(criteria);// 分页和排序Pageable pageable = PageRequest.of(request.getPage(), request.getSize(), Sort.by(Sort.Direction.fromString(request.getSortDirection()), request.getSortBy()));query.with(pageable);// 执行查询long count = mongoTemplate.count(query, Product.class);List<Product> products = mongoTemplate.find(query, Product.class);return new PageImpl<>(products, pageable, count);}@Override@Transactionalpublic void updateProductStock(String productId, int quantityChange) {// 使用原子操作更新库存Query query = new Query(Criteria.where("id").is(productId));Update update = new Update().inc("stock", quantityChange).currentDate("updateTime");UpdateResult result = mongoTemplate.updateFirst(query, update, Product.class);if (result.getMatchedCount() == 0) {throw new RuntimeException("Product not found");}// 清除缓存redisTemplate.delete(PRODUCT_CACHE_PREFIX + productId);}@Overridepublic List<CategoryStats> getCategoryStatistics() {// 使用聚合框架统计分类数据Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(Criteria.where("status").is("ACTIVE")),Aggregation.group("category").avg("price").as("avgPrice").sum("stock").as("totalStock").count().as("productCount"),Aggregation.sort(Sort.Direction.DESC, "productCount"));AggregationResults<CategoryStats> results = mongoTemplate.aggregate(aggregation, Product.class, CategoryStats.class);return results.getMappedResults();}
}
6.2.2 商品评价服务
@Service
public class ReviewServiceImpl implements ReviewService {@Autowiredprivate ReviewRepository reviewRepository;@Autowiredprivate MongoTemplate mongoTemplate;@Overridepublic Review addReview(Review review) {// 验证产品是否存在if (!mongoTemplate.exists(new Query(Criteria.where("id").is(review.getProductId())), Product.class)) {throw new RuntimeException("Product not found");}// 设置创建时间review.setCreateTime(new Date());// 保存评价Review savedReview = reviewRepository.save(review);// 更新产品的平均评分updateProductRating(review.getProductId());return savedReview;}private void updateProductRating(String productId) {// 使用聚合框架计算平均评分Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(Criteria.where("productId").is(productId)),Aggregation.group().avg("rating").as("avgRating"));AggregationResults<AverageRating> results = mongoTemplate.aggregate(aggregation, Review.class, AverageRating.class);Double avgRating = results.getMappedResults().isEmpty() ? 0.0 : results.getMappedResults().get(0).getAvgRating();// 更新产品评分Query query = new Query(Criteria.where("id").is(productId));Update update = new Update().set("averageRating", avgRating).currentDate("updateTime");mongoTemplate.updateFirst(query, update, Product.class);}@Overridepublic Page<Review> getProductReviews(String productId, Pageable pageable) {return reviewRepository.findByProductId(productId, pageable);}@Overridepublic List<RatingDistribution> getRatingDistribution(String productId) {Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(Criteria.where("productId").is(productId)),Aggregation.group("rating").count().as("count"),Aggregation.sort(Sort.Direction.ASC, "_id"));AggregationResults<RatingDistribution> results = mongoTemplate.aggregate(aggregation, Review.class, RatingDistribution.class);return results.getMappedResults();}// 聚合结果类private static class AverageRating {private Double avgRating;// getter/setter}private static class RatingDistribution {private Integer rating;private Long count;// getter/setter}
}
7. 测试策略
7.1 单元测试
@DataMongoTest
@ExtendWith(SpringExtension.class)
public class ProductRepositoryTest {@Autowiredprivate ProductRepository productRepository;@Autowiredprivate MongoTemplate mongoTemplate;@BeforeEachpublic void setup() {productRepository.deleteAll();// 初始化测试数据Product product1 = new Product();product1.setName("Laptop");product1.setCategory("Electronics");product1.setPrice(999.99);Product product2 = new Product();product2.setName("Smartphone");product2.setCategory("Electronics");product2.setPrice(699.99);productRepository.saveAll(Arrays.asList(product1, product2));}@Testpublic void testFindByCategory() {List<Product> electronics = productRepository.findByCategory("Electronics");assertEquals(2, electronics.size());}@Testpublic void testPriceRangeQuery() {List<Product> expensiveProducts = productRepository.findByPriceBetween(700.0, 1000.0);assertEquals(1, expensiveProducts.size());assertEquals("Laptop", expensiveProducts.get(0).getName());}
}
7.2 集成测试
@SpringBootTest
@Testcontainers
public class ProductServiceIntegrationTest {@Containerstatic MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:5.0");@DynamicPropertySourcestatic void setProperties(DynamicPropertyRegistry registry) {registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);}@Autowiredprivate ProductService productService;@Autowiredprivate ProductRepository productRepository;@Test@Transactionalpublic void testCreateAndRetrieveProduct() {Product product = new Product();product.setName("Test Product");product.setCategory("Test");product.setPrice(100.0);Product savedProduct = productService.createProduct(product);assertNotNull(savedProduct.getId());Product retrievedProduct = productService.getProductById(savedProduct.getId());assertEquals("Test Product", retrievedProduct.getName());}@Testpublic void testProductSearch() {ProductSearchRequest request = new ProductSearchRequest();request.setCategory("Electronics");request.setPage(0);request.setSize(10);Page<Product> result = productService.searchProducts(request);assertTrue(result.getTotalElements() > 0);}
}
8. 常见问题与解决方案
8.1 连接问题排查
问题现象:无法连接到 MongoDB 服务器
排查步骤:
- 检查连接字符串是否正确
- 验证网络连通性
- 检查认证信息
- 查看 MongoDB 服务器日志
// 测试连接
try {MongoClient client = MongoClients.create("mongodb://localhost:27017");client.listDatabaseNames().first();System.out.println("Connection successful");
} catch (Exception e) {System.err.println("Connection failed: " + e.getMessage());
}
8.2 性能问题排查
问题现象:查询响应慢
排查步骤:
- 使用 explain() 分析查询执行计划
Query query = new Query(Criteria.where("price").gt(100));
Document explain = mongoTemplate.getCollection("products").find(query.getQueryObject()).explain();
System.out.println(explain.toJson());
- 检查索引使用情况
- 分析 MongoDB 服务器资源使用情况
- 优化查询条件和索引
8.3 数据一致性问题
解决方案:
- 使用多文档事务(MongoDB 4.0+)
- 实现最终一致性模式
- 使用变更流监听数据变化
- 定期数据校验和修复
9. 未来发展与扩展
9.1 分片集群扩展
@Configuration
public class ShardingConfig {@Beanpublic MongoClient mongoClient() {// 配置分片集群连接ConnectionString connectionString = new ConnectionString("mongodb://shard1:27017,shard2:27017,shard3:27017/admin?replicaSet=shardRS");MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(connectionString).writeConcern(WriteConcern.MAJORITY).readPreference(ReadPreference.secondaryPreferred()).retryWrites(true).build();return MongoClients.create(settings);}
}
9.2 时间序列集合(MongoDB 5.0+)
@Document(collection = "sensor_readings")
@TimeSeries(collection = "sensor_readings", timeField = "timestamp", metaField = "sensorMetadata", granularity = TimeSeriesGranularity.SECONDS)
public class SensorReading {@Idprivate String id;private Date timestamp;private SensorMetadata sensorMetadata;private Double value;// getter/setter
}public class SensorMetadata {private String sensorId;private String location;private String type;
}
9.3 与 Atlas Search 集成
public List<Product> fullTextSearch(String query) {TextCriteria criteria = TextCriteria.forDefaultLanguage().matching(query).caseSensitive(false).diacriticSensitive(false);Query searchQuery = TextQuery.queryText(criteria).sortByScore().with(PageRequest.of(0, 10));return mongoTemplate.find(searchQuery, Product.class);
}
10. 总结
本文详细介绍了 SpringBoot 集成 MongoDB 的完整方案,涵盖以下内容:
- 环境准备:版本兼容性、依赖配置、连接设置
- 数据建模:实体映射、索引管理、关系处理
- 数据操作:基础CRUD、复杂查询、聚合框架
- 高级特性:事务管理、变更流、GridFS
- 性能优化:索引策略、查询优化、读写分离
- 实战案例:电商平台商品管理系统实现
- 测试策略:单元测试、集成测试方法
- 问题排查:连接问题、性能问题解决方案
- 未来扩展:分片集群、时间序列集合等
通过本指南,您应该能够在 SpringBoot 项目中高效地集成 MongoDB,构建高性能、可扩展的应用程序,并根据业务需求进行定制化开发。