Spring Boot 与 MongoDB 集成最佳实践构建灵活的数据存储系统引言MongoDB 是一个流行的 NoSQL 文档数据库以其灵活的数据模型和水平扩展能力而闻名。本文将详细介绍如何在 Spring Boot 项目中集成 MongoDB包括环境配置、实体映射、CRUD 操作、聚合查询、事务处理等核心功能。一、环境配置1.1 Maven 依赖dependencies !-- Spring Boot Data MongoDB Starter -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-mongodb/artifactId /dependency !-- Lombok (Optional) -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- Validation -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency /dependencies1.2 配置文件# application.yml spring: data: mongodb: uri: mongodb://localhost:27017/mydatabase username: admin password: password database: mydatabase auto-index-creation: true1.3 多数据源配置spring: data: mongodb: primary: uri: mongodb://localhost:27017/primarydb secondary: uri: mongodb://localhost:27017/secondarydb二、实体映射2.1 基础实体Document(collection users) Data NoArgsConstructor AllArgsConstructor public class User { Id private String id; Indexed(unique true) Field(username) private String username; Indexed(unique true) Field(email) private String email; Field(password_hash) private String passwordHash; Field(created_at) private LocalDateTime createdAt; Field(updated_at) private LocalDateTime updatedAt; Field(roles) private ListString roles new ArrayList(); PrePersist public void prePersist() { createdAt LocalDateTime.now(); updatedAt LocalDateTime.now(); } PreUpdate public void preUpdate() { updatedAt LocalDateTime.now(); } }2.2 嵌套文档Document(collection products) Data public class Product { Id private String id; Field(name) private String name; Field(description) private String description; Field(price) private BigDecimal price; Field(category) private Category category; Field(tags) private ListString tags; Field(stock) private Stock stock; Data public static class Category { private String id; private String name; private String parentId; } Data public static class Stock { private int quantity; private String warehouseId; private LocalDateTime lastUpdated; } }2.3 索引配置Component public class MongoIndexConfig { Autowired private MongoTemplate mongoTemplate; PostConstruct public void initIndexes() { // 用户集合索引 mongoTemplate.indexOps(User.class) .ensureIndex(new Index(email, Sort.Direction.ASC).unique()); // 产品集合复合索引 mongoTemplate.indexOps(Product.class) .ensureIndex(new Index(category.id, Sort.Direction.ASC) .on(price, Sort.Direction.DESC)); // 文本索引 mongoTemplate.indexOps(Product.class) .ensureIndex(new TextIndexDefinition.TextIndexDefinitionBuilder() .onField(name) .onField(description) .build()); } }三、Repository 接口3.1 基础 Repositorypublic interface UserRepository extends MongoRepositoryUser, String { OptionalUser findByUsername(String username); OptionalUser findByEmail(String email); ListUser findByRolesContaining(String role); ListUser findByCreatedAtBetween(LocalDateTime start, LocalDateTime end); Query({ email : { $regex: ?0 } }) ListUser findByEmailRegex(String pattern); }3.2 自定义 Repository 实现public interface UserRepositoryCustom { ListUser findUsersWithPagination(int page, int size); ListUser searchUsers(String keyword); } public class UserRepositoryImpl implements UserRepositoryCustom { Autowired private MongoTemplate mongoTemplate; Override public ListUser findUsersWithPagination(int page, int size) { return mongoTemplate.find(Query.query(Criteria.where(roles).in(USER)) .skip((long) page * size) .limit(size) .with(Sort.by(Sort.Direction.DESC, createdAt)), User.class); } Override public ListUser searchUsers(String keyword) { TextQuery query TextQuery.queryText(keyword) .sortByScore() .includeScore(); return mongoTemplate.find(query, User.class); } }四、CRUD 操作4.1 创建文档Service public class UserService { Autowired private UserRepository userRepository; public User createUser(UserCreateRequest request) { User user new User(); user.setUsername(request.getUsername()); user.setEmail(request.getEmail()); user.setPasswordHash(BCrypt.hashpw(request.getPassword(), BCrypt.gensalt())); user.setRoles(Arrays.asList(USER)); return userRepository.save(user); } public User createUserWithSession() { Session session mongoTemplate.getMongoDatabase().startSession(); try { session.startTransaction(); User user new User(); user.setUsername(test); user.setEmail(testexample.com); mongoTemplate.insert(user, session); // 创建关联数据 UserProfile profile new UserProfile(); profile.setUserId(user.getId()); mongoTemplate.insert(profile, session); session.commitTransaction(); return user; } catch (Exception e) { session.abortTransaction(); throw e; } finally { session.close(); } } }4.2 查询文档public User getUserById(String id) { return userRepository.findById(id) .orElseThrow(() - new ResourceNotFoundException(User not found)); } public ListUser getUsersByRole(String role) { return userRepository.findByRolesContaining(role); } public PageUser getUsersPage(int page, int size) { return userRepository.findAll(PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, createdAt))); } public User getUserByEmail(String email) { return userRepository.findByEmail(email) .orElse(null); }4.3 更新文档public User updateUser(String id, UserUpdateRequest request) { User user getUserById(id); if (request.getUsername() ! null) { user.setUsername(request.getUsername()); } if (request.getEmail() ! null) { user.setEmail(request.getEmail()); } return userRepository.save(user); } public void updateUserEmail(String userId, String newEmail) { Query query Query.query(Criteria.where(_id).is(userId)); Update update new Update() .set(email, newEmail) .set(updated_at, LocalDateTime.now()); mongoTemplate.updateFirst(query, update, User.class); } public void incrementUserLoginCount(String userId) { Query query Query.query(Criteria.where(_id).is(userId)); Update update new Update().inc(login_count, 1); mongoTemplate.updateFirst(query, update, User.class); }4.4 删除文档public void deleteUser(String id) { userRepository.deleteById(id); } public void deleteUsersByRole(String role) { Query query Query.query(Criteria.where(roles).in(role)); mongoTemplate.remove(query, User.class); }五、高级查询5.1 聚合查询public ListUserStatsDTO getUserStatsByRole() { Aggregation aggregation Aggregation.newAggregation( Aggregation.unwind(roles), Aggregation.group(roles) .count().as(userCount) .avg(age).as(avgAge), Aggregation.sort(Sort.Direction.DESC, userCount) ); AggregationResultsUserStatsDTO results mongoTemplate.aggregate( aggregation, users, UserStatsDTO.class); return results.getMappedResults(); } public ListProduct getProductsWithLowStock(int threshold) { Query query Query.query(Criteria.where(stock.quantity).lt(threshold)); return mongoTemplate.find(query, Product.class); }5.2 地理空间查询public ListStore findNearbyStores(double latitude, double longitude, double maxDistance) { Query query Query.query(Criteria.where(location) .nearSphere(new Point(longitude, latitude)) .maxDistance(maxDistance / 6378137)); // 转换为弧度 return mongoTemplate.find(query, Store.class); }5.3 文本搜索public ListProduct searchProducts(String keyword) { TextQuery query TextQuery.queryText(keyword) .sortByScore() .includeScore(); ListProduct products mongoTemplate.find(query, Product.class); // 设置匹配分数 products.forEach(p - { Double score (Double) mongoTemplate.getCollection(products) .find(query.getQueryObject()) .first() .get(score); // 处理分数 }); return products; }六、事务处理6.1 配置事务管理器Configuration EnableMongoTransactionManagement public class MongoTransactionConfig { Bean public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) { return new MongoTransactionManager(dbFactory); } }6.2 使用事务Service public class OrderService { Autowired private OrderRepository orderRepository; Autowired private InventoryRepository inventoryRepository; Transactional public Order createOrder(OrderCreateRequest request) { // 创建订单 Order order new Order(); order.setUserId(request.getUserId()); order.setItems(request.getItems()); order.setTotalAmount(request.getTotalAmount()); order orderRepository.save(order); // 扣减库存 for (OrderItem item : request.getItems()) { Query query Query.query(Criteria.where(productId).is(item.getProductId())); Update update new Update().inc(quantity, -item.getQuantity()); mongoTemplate.updateFirst(query, update, Inventory.class); } return order; } }七、批量操作7.1 批量插入public void batchInsertUsers(ListUser users) { mongoTemplate.insertAll(users); } public void batchInsertWithSession(ListUser users) { Session session mongoTemplate.getMongoDatabase().startSession(); try { session.startTransaction(); MongoCollectionDocument collection mongoTemplate.getCollection(users); ListDocument documents users.stream() .map(user - { Document doc new Document(); doc.append(username, user.getUsername()); doc.append(email, user.getEmail()); doc.append(created_at, user.getCreatedAt()); return doc; }) .collect(Collectors.toList()); collection.insertMany(documents); session.commitTransaction(); } catch (Exception e) { session.abortTransaction(); throw e; } finally { session.close(); } }7.2 批量更新public void batchUpdateUserStatus(ListString userIds, String status) { Query query Query.query(Criteria.where(_id).in(userIds)); Update update new Update().set(status, status); mongoTemplate.updateMulti(query, update, User.class); }八、性能优化8.1 索引优化Component public class IndexOptimizer { Autowired private MongoTemplate mongoTemplate; public void analyzeQueryPerformance(Query query, Class? entityClass) { ExplainCursorDocument explain mongoTemplate.getCollection( mongoTemplate.getCollectionName(entityClass)) .explain(query.getQueryObject()); Document executionStats (Document) explain.first().get(executionStats); System.out.println(Execution Time: executionStats.get(executionTimeMillis)); System.out.println(Total Docs Examined: executionStats.get(totalDocsExamined)); System.out.println(Total Keys Examined: executionStats.get(totalKeysExamined)); } }8.2 读写分离Configuration public class MongoReplicaConfig { Bean Primary public MongoTemplate primaryMongoTemplate(MongoClient mongoClient) { return new MongoTemplate(mongoClient, primarydb); } Bean public MongoTemplate secondaryMongoTemplate(MongoClient mongoClient) { MongoDatabase db mongoClient.getDatabase(secondarydb); db.withReadPreference(ReadPreference.secondaryPreferred()); return new MongoTemplate(mongoClient, secondarydb); } }8.3 数据分片Configuration public class MongoShardingConfig { Bean public MongoClient mongoClient() { ConnectionString connectionString new ConnectionString( mongodb://mongos1:27017,mongos2:27017/mydatabase); MongoClientSettings settings MongoClientSettings.builder() .applyConnectionString(connectionString) .build(); return MongoClients.create(settings); } }九、监控与管理9.1 健康检查Component public class MongoHealthIndicator implements HealthIndicator { Autowired private MongoTemplate mongoTemplate; Override public Health health() { try { mongoTemplate.getDb().runCommand(new Document(ping, 1)); return Health.up().build(); } catch (Exception e) { return Health.down(e).build(); } } }9.2 指标监控Component public class MongoMetrics { private final Counter queriesCounter; private final Counter insertsCounter; private final Counter updatesCounter; private final Counter deletesCounter; public MongoMetrics(MeterRegistry meterRegistry) { this.queriesCounter Counter.builder(mongodb.queries) .register(meterRegistry); this.insertsCounter Counter.builder(mongodb.inserts) .register(meterRegistry); this.updatesCounter Counter.builder(mongodb.updates) .register(meterRegistry); this.deletesCounter Counter.builder(mongodb.deletes) .register(meterRegistry); } public void recordQuery() { queriesCounter.increment(); } public void recordInsert() { insertsCounter.increment(); } public void recordUpdate() { updatesCounter.increment(); } public void recordDelete() { deletesCounter.increment(); } }十、最佳实践10.1 集合命名规范使用小写字母和下划线 复数形式 例如: users, products, orders10.2 字段命名规范使用小写字母和下划线 避免使用保留字 例如: user_id, created_at, is_active10.3 索引策略// 复合索引 mongoTemplate.indexOps(orders) .ensureIndex(new Index(user_id, Sort.Direction.ASC) .on(created_at, Sort.Direction.DESC)); // 唯一索引 mongoTemplate.indexOps(users) .ensureIndex(new Index(email, Sort.Direction.ASC).unique()); // TTL 索引自动过期 mongoTemplate.indexOps(sessions) .ensureIndex(new Index(expire_at, Sort.Direction.ASC) .expire(0, TimeUnit.SECONDS));10.4 数据模型设计// 嵌入式文档一对一关系 Field(address) private Address address; // 引用文档一对多关系 Field(order_ids) private ListString orderIds; // 数组字段多值属性 Field(tags) private ListString tags;十一、总结MongoDB 为 Spring Boot 应用提供了灵活的数据存储解决方案。通过合理配置和使用可以构建高性能、可扩展的数据库系统。在实际应用中需要注意以下几点索引优化: 创建适当的索引提高查询性能数据模型设计: 根据业务需求选择合适的数据结构事务处理: 使用事务保证数据一致性监控告警: 及时发现和处理问题希望本文能帮助你在 Spring Boot 项目中成功集成 MongoDB