news 2026/6/2 19:49:43

SpringBoot整合MongoDB,性能提升,优化实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot整合MongoDB,性能提升,优化实践

大家好,我是小悟。

一、MongoDB简介

MongoDB是一个基于分布式文件存储的NoSQL数据库,具有以下特点:

  1. 文档型数据库:数据以BSON(Binary JSON)格式存储,结构灵活
  2. 无模式设计:集合中的文档可以有不同的字段,无需预先定义表结构
  3. 高性能:支持索引、聚合管道、丰富的查询语言
  4. 高可用性:通过副本集实现数据冗余和故障转移
  5. 水平扩展:通过分片集群实现数据水平拆分
  6. 丰富的查询功能:支持丰富的查询操作符和聚合框架

二、整合步骤与代码实现

1. 环境准备

pom.xml 依赖配置:

<dependencies> <!-- Spring Boot Starter Data MongoDB --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <!-- Spring Boot Starter Web (可选,用于REST API) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Lombok (简化代码) --> <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> </dependencies>

application.yml 配置:

spring: data: mongodb: # 连接字符串格式 uri: mongodb://localhost:27017/testdb # 或者分开配置 # host: localhost # port: 27017 # database: testdb # username: user # password: pass # 连接池配置 auto-index-creation: true # 自定义配置 mongodb: collection: user: users product: products

2. 实体类定义

package com.example.mongodemo.entity; import lombok.Data; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Builder; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; import java.time.LocalDateTime; import java.util.List; /** * 用户实体类 * @Document 指定MongoDB集合名称 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @Document(collection = "users") // 对应集合名 public class User { @Id // MongoDB主键 private String id; @Field("username") // 指定字段名,可选 private String username; private String email; private Integer age; private Address address; // 嵌套文档 private List<String> hobbies; // 数组类型 private LocalDateTime createTime; @Field("is_active") private Boolean isActive; /** * 嵌套文档示例 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class Address { private String city; private String street; private String zipCode; } }

3. Repository接口

package com.example.mongodemo.repository; import com.example.mongodemo.entity.User; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; import java.util.Optional; /** * 用户Repository * 继承MongoRepository获得CRUD基本操作 */ @Repository public interface UserRepository extends MongoRepository<User, String> { // 自定义查询方法 - 根据方法名自动生成查询 List<User> findByUsername(String username); List<User> findByAgeGreaterThan(int age); List<User> findByEmailContaining(String domain); Optional<User> findByUsernameAndEmail(String username, String email); long countByIsActiveTrue(); // 使用@Query注解自定义查询 @Query("{ 'age' : { $gt: ?0, $lt: ?1 } }") List<User> findUsersByAgeBetween(int min, int max); @Query("{ 'address.city' : ?0 }") List<User> findByCity(String city); @Query("{ 'hobbies' : { $in: ?0 } }") List<User> findByHobbiesIn(List<String> hobbies); // 使用正则表达式查询 @Query("{ 'email' : { $regex: ?0 } }") List<User> findByEmailPattern(String pattern); }

4. 自定义Repository实现

package com.example.mongodemo.repository.custom; import com.example.mongodemo.entity.User; import java.util.List; public interface CustomUserRepository { List<User> findActiveUsersWithCustomQuery(); void updateUserEmail(String userId, String newEmail); } package com.example.mongodemo.repository.custom.impl; import com.example.mongodemo.entity.User; import com.example.mongodemo.repository.custom.CustomUserRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; import java.util.List; @Repository @RequiredArgsConstructor public class CustomUserRepositoryImpl implements CustomUserRepository { private final MongoTemplate mongoTemplate; @Override public List<User> findActiveUsersWithCustomQuery() { Query query = new Query(); query.addCriteria(Criteria.where("isActive").is(true)) .addCriteria(Criteria.where("age").gte(18)); return mongoTemplate.find(query, User.class); } @Override public void updateUserEmail(String userId, String newEmail) { Query query = new Query(Criteria.where("id").is(userId)); Update update = new Update(); update.set("email", newEmail); mongoTemplate.updateFirst(query, update, User.class); } }

5. 更新主Repository接口

package com.example.mongodemo.repository; import com.example.mongodemo.entity.User; import com.example.mongodemo.repository.custom.CustomUserRepository; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends MongoRepository<User, String>, CustomUserRepository { // 方法继承自两个接口 }

6. Service层实现

package com.example.mongodemo.service; import com.example.mongodemo.entity.User; import com.example.mongodemo.repository.UserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @Service @RequiredArgsConstructor @Slf4j public class UserService { private final UserRepository userRepository; /** * 创建用户 */ public User createUser(User user) { user.setCreateTime(LocalDateTime.now()); if (user.getIsActive() == null) { user.setIsActive(true); } return userRepository.save(user); } /** * 批量插入用户 */ public List<User> batchCreateUsers(List<User> users) { users.forEach(user -> { user.setCreateTime(LocalDateTime.now()); if (user.getIsActive() == null) { user.setIsActive(true); } }); return userRepository.saveAll(users); } /** * 根据ID查询用户 */ public Optional<User> getUserById(String id) { return userRepository.findById(id); } /** * 查询所有活跃用户 */ public List<User> getActiveUsers() { return userRepository.findByIsActiveTrue(); } /** * 分页查询用户 */ public Page<User> getUsersByPage(Pageable pageable) { return userRepository.findAll(pageable); } /** * 根据用户名和邮箱查询 */ public Optional<User> getUserByUsernameAndEmail(String username, String email) { return userRepository.findByUsernameAndEmail(username, email); } /** * 更新用户邮箱 */ public boolean updateUserEmail(String userId, String newEmail) { Optional<User> userOpt = userRepository.findById(userId); if (userOpt.isPresent()) { User user = userOpt.get(); user.setEmail(newEmail); userRepository.save(user); return true; } return false; } /** * 使用自定义查询更新邮箱 */ public void updateUserEmailWithCustom(String userId, String newEmail) { userRepository.updateUserEmail(userId, newEmail); } /** * 删除用户 */ public boolean deleteUser(String id) { if (userRepository.existsById(id)) { userRepository.deleteById(id); return true; } return false; } /** * 根据年龄范围查询用户 */ public List<User> findUsersByAgeRange(int minAge, int maxAge) { return userRepository.findUsersByAgeBetween(minAge, maxAge); } /** * 统计活跃用户数量 */ public long countActiveUsers() { return userRepository.countByIsActiveTrue(); } }

7. Controller层

package com.example.mongodemo.controller; import com.example.mongodemo.entity.User; import com.example.mongodemo.service.UserService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; @RestController @RequestMapping("/api/users") @RequiredArgsConstructor public class UserController { private final UserService userService; @PostMapping public ResponseEntity<User> createUser(@RequestBody User user) { User savedUser = userService.createUser(user); return ResponseEntity.status(HttpStatus.CREATED).body(savedUser); } @PostMapping("/batch") public ResponseEntity<List<User>> batchCreateUsers(@RequestBody List<User> users) { List<User> savedUsers = userService.batchCreateUsers(users); return ResponseEntity.status(HttpStatus.CREATED).body(savedUsers); } @GetMapping("/{id}") public ResponseEntity<User> getUserById(@PathVariable String id) { Optional<User> user = userService.getUserById(id); return user.map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @GetMapping public ResponseEntity<Page<User>> getAllUsers( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(defaultValue = "createTime") String sortBy) { Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy).descending()); Page<User> users = userService.getUsersByPage(pageable); return ResponseEntity.ok(users); } @GetMapping("/active") public ResponseEntity<List<User>> getActiveUsers() { List<User> activeUsers = userService.getActiveUsers(); return ResponseEntity.ok(activeUsers); } @GetMapping("/age-range") public ResponseEntity<List<User>> getUsersByAgeRange( @RequestParam int minAge, @RequestParam int maxAge) { List<User> users = userService.findUsersByAgeRange(minAge, maxAge); return ResponseEntity.ok(users); } @PutMapping("/{id}/email") public ResponseEntity<Void> updateEmail( @PathVariable String id, @RequestParam String newEmail) { boolean updated = userService.updateUserEmail(id, newEmail); return updated ? ResponseEntity.ok().build() : ResponseEntity.notFound().build(); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable String id) { boolean deleted = userService.deleteUser(id); return deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build(); } @GetMapping("/stats/active-count") public ResponseEntity<Long> getActiveUserCount() { long count = userService.countActiveUsers(); return ResponseEntity.ok(count); } }

8. 聚合查询示例

package com.example.mongodemo.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.AggregationResults; import org.springframework.data.mongodb.core.aggregation.GroupOperation; import org.springframework.data.mongodb.core.aggregation.MatchOperation; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; @Service @RequiredArgsConstructor @Slf4j public class UserAggregationService { private final MongoTemplate mongoTemplate; /** * 按城市分组统计用户数量 */ public List<UserCityStats> groupUsersByCity() { GroupOperation groupByCity = Aggregation.group("address.city") .count().as("userCount") .avg("age").as("averageAge"); Aggregation aggregation = Aggregation.newAggregation(groupByCity); AggregationResults<UserCityStats> results = mongoTemplate.aggregate(aggregation, "users", UserCityStats.class); return results.getMappedResults(); } /** * 统计各年龄段用户数量 */ public List<AgeGroupStats> groupUsersByAgeGroup() { GroupOperation groupByAgeGroup = Aggregation.group( Aggregation.function("cond", Aggregation.function("and", Aggregation.function("gte", "age", 0), Aggregation.function("lte", "age", 18) ), "0-18", Aggregation.function("cond", Aggregation.function("and", Aggregation.function("gt", "age", 18), Aggregation.function("lte", "age", 30) ), "19-30", "30+" ) ) ).count().as("count"); Aggregation aggregation = Aggregation.newAggregation(groupByAgeGroup); AggregationResults<AgeGroupStats> results = mongoTemplate.aggregate(aggregation, "users", AgeGroupStats.class); return results.getMappedResults(); } // 统计结果类 public static class UserCityStats { private String city; private Long userCount; private Double averageAge; // getters and setters } public static class AgeGroupStats { private String ageGroup; private Long count; // getters and setters } }

9. 事务支持(需要MongoDB副本集)

package com.example.mongodemo.service; import com.example.mongodemo.entity.User; import com.example.mongodemo.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; @Service @RequiredArgsConstructor public class TransactionalUserService { private final UserRepository userRepository; /** * 事务操作示例 * 注意:MongoDB事务需要副本集 */ @Transactional(rollbackFor = Exception.class) public void createUserWithTransaction(User user1, User user2) { // 保存第一个用户 user1.setCreateTime(LocalDateTime.now()); user1.setIsActive(true); userRepository.save(user1); // 模拟业务逻辑 if (user1.getEmail() == null) { throw new RuntimeException("Email is required"); } // 保存第二个用户 user2.setCreateTime(LocalDateTime.now()); user2.setIsActive(true); userRepository.save(user2); } }

10. 配置类

package com.example.mongodemo.config; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.config.EnableMongoAuditing; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @Configuration @EnableMongoRepositories(basePackages = "com.example.mongodemo.repository") @EnableMongoAuditing // 启用审计功能 public class MongoConfig { // 可以配置MongoTemplate的自定义设置 // @Bean // public MongoTemplate mongoTemplate(MongoDatabaseFactory factory) { // return new MongoTemplate(factory); // } }

11. 审计功能(自动填充创建/更新时间)

package com.example.mongodemo.entity; import lombok.Data; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.mongodb.core.mapping.Document; import java.time.LocalDateTime; @Data @Document(collection = "auditable_entities") public class AuditableEntity { private String id; private String name; @CreatedDate private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime updatedAt; }

12. 测试类

package com.example.mongodemo; import com.example.mongodemo.entity.User; import com.example.mongodemo.repository.UserRepository; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import java.util.Arrays; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest class MongoDemoApplicationTests { @Autowired private UserRepository userRepository; @Test void testCRUDOperations() { // 创建用户 User user = User.builder() .username("testuser") .email("test@example.com") .age(25) .isActive(true) .hobbies(Arrays.asList("reading", "sports")) .build(); // 保存 User savedUser = userRepository.save(user); assertThat(savedUser.getId()).isNotNull(); // 查询 List<User> users = userRepository.findByUsername("testuser"); assertThat(users).hasSize(1); // 更新 savedUser.setEmail("updated@example.com"); userRepository.save(savedUser); // 删除 userRepository.delete(savedUser); // 验证删除 long count = userRepository.count(); assertThat(count).isEqualTo(0); } @Test void testPagination() { // 创建测试数据 for (int i = 0; i < 15; i++) { User user = User.builder() .username("user" + i) .email("user" + i + "@example.com") .age(20 + i) .isActive(true) .build(); userRepository.save(user); } // 分页查询 Page<User> page = userRepository.findAll(PageRequest.of(0, 10)); assertThat(page.getContent()).hasSize(10); assertThat(page.getTotalElements()).isEqualTo(15); } }

三、总结

1. 整合优势

Spring Data MongoDB提供了:

  • 简化的操作:通过Repository接口减少大量模板代码
  • 强大的查询:支持方法名查询、@Query注解、Criteria API
  • 对象映射:自动将文档映射为Java对象
  • 事务支持:支持MongoDB 4.0+的事务功能
  • 聚合框架:支持复杂的聚合操作
  • 审计功能:自动填充创建/更新时间

2. 最佳实践

  1. 连接配置:使用连接池提高性能,合理设置连接参数
  2. 索引优化:为频繁查询的字段创建索引
  3. 文档设计:合理设计文档结构,避免过度嵌套
  4. 批量操作:使用批量操作提高数据插入/更新效率
  5. 读写分离:考虑使用副本集实现读写分离

3. 注意事项

  1. 事务要求:MongoDB事务需要副本集环境
  2. 内存管理:注意大文档的内存消耗
  3. 连接管理:合理配置连接池大小
  4. 数据建模:根据查询模式设计文档结构
  5. 索引策略:避免过多的索引影响写入性能

4. 适用场景

  • 内容管理系统:文章、评论等半结构化数据
  • 物联网应用:设备日志、传感器数据
  • 实时分析:用户行为分析、实时统计
  • 社交应用:用户动态、消息数据
  • 电商平台:商品信息、用户收藏

SpringBoot与MongoDB的整合提供了高效、灵活的数据存储方案,特别适合处理半结构化、快速增长的数据场景。通过Spring Data MongoDB的封装,可以像操作传统关系型数据库一样操作MongoDB,同时享受NoSQL数据库的灵活性和扩展性优势。

谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。

您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 5:14:27

智能抠图Rembg:汽车图片处理实战

智能抠图Rembg&#xff1a;汽车图片处理实战 1. 引言&#xff1a;智能万能抠图 - Rembg 在图像处理领域&#xff0c;自动去背景一直是高频且关键的需求&#xff0c;尤其在电商、广告设计、AI生成内容&#xff08;AIGC&#xff09;等场景中&#xff0c;高质量的透明图是提升视…

作者头像 李华
网站建设 2026/5/28 14:24:33

自动化测试未来趋势:AI、ML与新兴技术

在软件开发生命周期中&#xff0c;自动化测试已成为提升效率、保障质量的核心环节。随着人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&#xff09;及新兴技术的崛起&#xff0c;测试领域正经历革命性变革。本文深入探讨未来趋势&#xff0c;为测试从业者提供战…

作者头像 李华
网站建设 2026/5/28 14:24:35

5分钟快速原型:构建null安全的数据展示组件

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 生成一个React/Vue组件模板&#xff0c;专门用于安全渲染可能为null的数组数据。要求&#xff1a;1) 支持三种渲染模式(隐藏/占位符/默认值) 2) 包含TypeScript类型守卫 3) 可配置…

作者头像 李华
网站建设 2026/5/28 23:36:12

Rembg模型解析:显著性目标检测原理详解

Rembg模型解析&#xff1a;显著性目标检测原理详解 1. 智能万能抠图 - Rembg 在图像处理与计算机视觉领域&#xff0c;自动去背景&#xff08;Image Matting&#xff09;一直是极具挑战性的任务。传统方法依赖于用户手动标注前景区域或使用简单的颜色阈值分割&#xff0c;不仅…

作者头像 李华
网站建设 2026/5/28 14:24:41

Rembg性能优化:缓存机制实现教程

Rembg性能优化&#xff1a;缓存机制实现教程 1. 引言 1.1 智能万能抠图 - Rembg 在图像处理与内容创作领域&#xff0c;自动去背景技术已成为提升效率的关键工具。Rembg 作为一款基于深度学习的开源图像分割工具&#xff0c;凭借其高精度、通用性强和易集成等优势&#xff0…

作者头像 李华
网站建设 2026/5/28 22:48:51

用Flex布局5分钟搭建网页原型:设计师必备技能

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 生成一个网页原型框架&#xff0c;使用display: flex快速实现头部、侧边栏、内容区和页脚的基本布局。要求代码简洁&#xff0c;易于修改&#xff0c;并支持快速添加占位内容。点击…

作者头像 李华