Spring Boot 整合 MongoDB 最佳实践:CRUD、分页、事务、索引全覆盖
大家好我是小悟。一、需求描述业务场景开发一个博客文章管理系统实现文章的基本CRUD操作支持文章的评论功能支持根据标题和内容模糊搜索记录文章的创建和更新时间支持文章标签管理技术需求使用Spring Boot 2.x使用MongoDB存储数据提供RESTful API接口使用MongoTemplate和MongoRepository两种方式操作数据二、详细步骤1. 环境准备安装MongoDB# MacOS brew install mongodb-community brew services start mongodb-community # 验证安装 mongo --version2. 创建Spring Boot项目pom.xml依赖配置?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.0/version /parent groupIdcom.example/groupId artifactIdmongodb-demo/artifactId version1.0.0/version properties java.version1.8/java.version /properties dependencies !-- Spring Boot Web -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring Data MongoDB -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-mongodb/artifactId /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- 测试依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build /project3. 配置文件application.ymlspring: data: mongodb: host: localhost port: 27017 database: blogdb # 如果需要认证 # username: admin # password: admin123 # authentication-database: admin server: port: 8080 logging: level: org.springframework.data.mongodb: DEBUG4. 实体类设计Article.javapackage com.example.mongodb.entity; import lombok.Data; import lombok.Builder; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; import java.time.LocalDateTime; import java.util.List; Data Builder NoArgsConstructor AllArgsConstructor Document(collection articles) // 指定集合名称 public class Article { Id private String id; // MongoDB默认使用ObjectId这里用String接收 Indexed(unique true) // 创建唯一索引 private String title; Field(content) // 指定字段名 private String content; private String author; private ListString tags; private Integer viewCount; private ListComment comments; Field(createTime) private LocalDateTime createTime; Field(updateTime) private LocalDateTime updateTime; private Boolean published; Data Builder NoArgsConstructor AllArgsConstructor public static class Comment { private String username; private String content; private LocalDateTime commentTime; private Integer likes; } }5. Repository层使用MongoRepository方式package com.example.mongodb.repository; import com.example.mongodb.entity.Article; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; Repository public interface ArticleRepository extends MongoRepositoryArticle, String { // 根据作者查询 ListArticle findByAuthor(String author); // 根据标签查询 ListArticle findByTagsIn(ListString tags); // 根据标题模糊查询 ListArticle findByTitleLike(String title); // 根据发布时间范围查询 ListArticle findByCreateTimeBetween(LocalDateTime start, LocalDateTime end); // 使用Query注解自定义查询 Query({title: {$regex: ?0}, published: true}) ListArticle findPublishedArticlesByTitle(String title); // 复杂的嵌套查询 Query({comments.username: ?0}) ListArticle findByCommentUsername(String username); }使用MongoTemplate方式package com.example.mongodb.repository; import com.example.mongodb.entity.Article; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; 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 public class ArticleTemplateRepository { Autowired private MongoTemplate mongoTemplate; // 条件查询 public ListArticle findByCondition(String keyword, String author) { Query query new Query(); // 添加查询条件 if (keyword ! null !keyword.isEmpty()) { query.addCriteria(Criteria.where(title).regex(keyword) .orOperator(Criteria.where(content).regex(keyword))); } if (author ! null !author.isEmpty()) { query.addCriteria(Criteria.where(author).is(author)); } // 只查询已发布的文章 query.addCriteria(Criteria.where(published).is(true)); // 排序 query.with(Sort.by(Sort.Direction.DESC, createTime)); return mongoTemplate.find(query, Article.class); } // 更新评论点赞数 public void updateCommentLikes(String articleId, String commentUsername, int increment) { Query query new Query(Criteria.where(id).is(articleId) .and(comments.username).is(commentUsername)); Update update new Update().inc(comments.$.likes, increment); mongoTemplate.updateFirst(query, update, Article.class); } // 增加文章浏览量 public void incrementViewCount(String articleId) { Query query new Query(Criteria.where(id).is(articleId)); Update update new Update().inc(viewCount, 1); mongoTemplate.updateFirst(query, update, Article.class); } // 批量更新 public void updateArticlesStatusByAuthor(String author, Boolean status) { Query query new Query(Criteria.where(author).is(author)); Update update new Update().set(published, status); mongoTemplate.updateMulti(query, update, Article.class); } }6. Service层package com.example.mongodb.service; import com.example.mongodb.entity.Article; import com.example.mongodb.repository.ArticleRepository; import com.example.mongodb.repository.ArticleTemplateRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import java.util.UUID; Service public class ArticleService { Autowired private ArticleRepository articleRepository; Autowired private ArticleTemplateRepository articleTemplateRepository; // 创建文章 public Article createArticle(Article article) { article.setId(null); // 确保是新文章 article.setCreateTime(LocalDateTime.now()); article.setUpdateTime(LocalDateTime.now()); article.setViewCount(0); return articleRepository.save(article); } // 更新文章 public Article updateArticle(String id, Article article) { return articleRepository.findById(id) .map(existingArticle - { article.setId(id); article.setCreateTime(existingArticle.getCreateTime()); article.setUpdateTime(LocalDateTime.now()); return articleRepository.save(article); }) .orElseThrow(() - new RuntimeException(文章不存在)); } // 删除文章 public void deleteArticle(String id) { articleRepository.deleteById(id); } // 查询单篇文章 public Article getArticle(String id) { return articleRepository.findById(id) .map(article - { // 阅读量1 articleTemplateRepository.incrementViewCount(id); article.setViewCount(article.getViewCount() 1); return article; }) .orElseThrow(() - new RuntimeException(文章不存在)); } // 查询所有文章 public ListArticle getAllArticles() { return articleRepository.findAll(); } // 根据作者查询 public ListArticle getArticlesByAuthor(String author) { return articleRepository.findByAuthor(author); } // 条件搜索 public ListArticle searchArticles(String keyword, String author) { return articleTemplateRepository.findByCondition(keyword, author); } // 添加评论 public Article addComment(String articleId, Article.Comment comment) { return articleRepository.findById(articleId) .map(article - { comment.setCommentTime(LocalDateTime.now()); comment.setLikes(0); article.getComments().add(comment); article.setUpdateTime(LocalDateTime.now()); return articleRepository.save(article); }) .orElseThrow(() - new RuntimeException(文章不存在)); } // 点赞评论 public void likeComment(String articleId, String username) { articleTemplateRepository.updateCommentLikes(articleId, username, 1); } }7. Controller层package com.example.mongodb.controller; import com.example.mongodb.entity.Article; import com.example.mongodb.service.ArticleService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; RestController RequestMapping(/api/articles) public class ArticleController { Autowired private ArticleService articleService; PostMapping public ResponseEntityArticle createArticle(RequestBody Article article) { Article created articleService.createArticle(article); return new ResponseEntity(created, HttpStatus.CREATED); } PutMapping(/{id}) public ResponseEntityArticle updateArticle(PathVariable String id, RequestBody Article article) { Article updated articleService.updateArticle(id, article); return ResponseEntity.ok(updated); } DeleteMapping(/{id}) public ResponseEntityVoid deleteArticle(PathVariable String id) { articleService.deleteArticle(id); return ResponseEntity.noContent().build(); } GetMapping(/{id}) public ResponseEntityArticle getArticle(PathVariable String id) { Article article articleService.getArticle(id); return ResponseEntity.ok(article); } GetMapping public ResponseEntityListArticle getAllArticles() { ListArticle articles articleService.getAllArticles(); return ResponseEntity.ok(articles); } GetMapping(/search) public ResponseEntityListArticle searchArticles( RequestParam(required false) String keyword, RequestParam(required false) String author) { ListArticle articles articleService.searchArticles(keyword, author); return ResponseEntity.ok(articles); } PostMapping(/{id}/comments) public ResponseEntityArticle addComment( PathVariable String id, RequestBody Article.Comment comment) { Article article articleService.addComment(id, comment); return ResponseEntity.ok(article); } PostMapping(/{id}/comments/{username}/like) public ResponseEntityVoid likeComment( PathVariable String id, PathVariable String username) { articleService.likeComment(id, username); return ResponseEntity.ok().build(); } }8. 启动类package com.example.mongodb; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.mongodb.config.EnableMongoAuditing; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; SpringBootApplication EnableMongoRepositories // 启用MongoDB仓库 EnableMongoAuditing // 启用MongoDB审计功能 public class MongodbApplication { public static void main(String[] args) { SpringApplication.run(MongodbApplication.class, args); } }9. 测试数据初始化package com.example.mongodb.config; import com.example.mongodb.entity.Article; import com.example.mongodb.repository.ArticleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.Arrays; Component public class DataInitializer implements CommandLineRunner { Autowired private ArticleRepository articleRepository; Override public void run(String... args) throws Exception { // 清空数据 articleRepository.deleteAll(); // 创建测试文章 Article article1 Article.builder() .title(Spring Boot 入门教程) .content(本文将介绍Spring Boot的基本使用方法...) .author(张三) .tags(Arrays.asList(Java, Spring Boot, 教程)) .viewCount(0) .published(true) .createTime(LocalDateTime.now()) .updateTime(LocalDateTime.now()) .comments(Arrays.asList( Article.Comment.builder() .username(李四) .content(写的很好学习了) .commentTime(LocalDateTime.now()) .likes(5) .build() )) .build(); Article article2 Article.builder() .title(MongoDB 实战技巧) .content(分享MongoDB在实际项目中的应用经验...) .author(王五) .tags(Arrays.asList(数据库, MongoDB, 实战)) .viewCount(0) .published(true) .createTime(LocalDateTime.now()) .updateTime(LocalDateTime.now()) .comments(Arrays.asList()) .build(); articleRepository.saveAll(Arrays.asList(article1, article2)); System.out.println(测试数据初始化完成); } }三、测试接口使用curl测试API# 创建文章 curl -X POST http://localhost:8080/api/articles \ -H Content-Type: application/json \ -d { title: MongoDB高级特性, content: 本文将介绍MongoDB的高级特性..., author: 赵六, tags: [MongoDB, 数据库, 高级], published: true } # 查询所有文章 curl http://localhost:8080/api/articles # 搜索文章 curl http://localhost:8080/api/articles/search?keywordSpringauthor张三 # 添加评论 curl -X POST http://localhost:8080/api/articles/{id}/comments \ -H Content-Type: application/json \ -d { username: 读者A, content: 非常实用的教程 } # 点赞评论 curl -X POST http://localhost:8080/api/articles/{id}/comments/读者A/like四、详细总结1. MongoDB与关系型数据库的对比特性MongoDBMySQL数据结构文档型BSON/JSON表格行/列关联查询内嵌文档或DBRefJOIN操作Schema动态schema固定schema扩展性原生支持水平扩展主从复制/分库分表事务支持4.0后支持多文档事务完整ACID支持2. Spring Data MongoDB的核心注解注解作用Document映射MongoDB的集合Id标识文档ID字段Field指定字段名Indexed声明索引CompoundIndex复合索引DBRef引用其他集合谨慎使用Transactional支持事务操作3. 操作方式对比MongoRepository的优点代码简洁继承接口即可获得基础CRUD支持方法名解析查询与Spring Data JPA使用方式相似MongoTemplate的优点更灵活的查询条件构造支持批量操作和聚合查询可以执行原生MongoDB命令4. 最佳实践建议1. 索引设计为常用查询字段创建索引复合索引要注意字段顺序使用Indexed注解或mongoTemplate创建索引2. 性能优化// 分页查询示例 Pageable pageable PageRequest.of(0, 10, Sort.by(createTime).descending()); PageArticle page articleRepository.findAll(pageable); // 只返回需要的字段 Query query new Query(); query.fields().include(title).include(author);3. 数据一致性Transactional public void updateWithTransaction(String articleId, Comment comment) { // 确保两个操作原子性 addComment(articleId, comment); updateArticleStats(articleId); }4. 异常处理ControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(DuplicateKeyException.class) public ResponseEntityString handleDuplicateKey() { return ResponseEntity.status(HttpStatus.CONFLICT) .body(文章标题已存在); } }5. 常见问题解决1. 连接认证问题spring: data: mongodb: uri: mongodb://username:passwordlocalhost:27017/dbname?authSourceadmin2. 大数据量处理// 使用流式处理 Autowired private MongoTemplate mongoTemplate; public void processLargeData() { Query query new Query(); query.cursorBatchSize(1000); // 设置批处理大小 mongoTemplate.stream(query, Article.class) .forEach(article - { // 处理每条记录 }); }3. 审计功能EntityListeners(AuditingEntityListener.class) public class Article { CreatedDate private LocalDateTime createTime; LastModifiedDate private LocalDateTime updateTime; }6. 项目结构建议src/main/java/com/example/mongodb/ ├── config/ # 配置类 ├── entity/ # 实体类 ├── repository/ # 数据访问层 ├── service/ # 业务逻辑层 ├── controller/ # REST控制器 ├── dto/ # 数据传输对象 ├── exception/ # 异常处理 └── util/ # 工具类五、总结通过本实战项目我们完整地实现了Spring Boot与MongoDB的整合涵盖了基础配置Maven依赖、YAML配置数据建模文档设计、嵌套文档使用数据访问Repository和Template两种方式业务实现CRUD操作、复杂查询、评论功能性能优化索引、分页、批量处理最佳实践事务、审计、异常处理MongoDB作为NoSQL数据库的代表特别适合以下场景数据结构不固定需要频繁变更需要快速迭代开发读写并发高需要水平扩展存储复杂嵌套结构的JSON数据Spring Data MongoDB提供了简洁的API让开发者能够专注于业务逻辑快速构建高性能的应用。通过合理使用MongoDB的特性可以充分发挥其文档数据库的优势。谢谢你看我的文章既然看到这里了如果觉得不错随手点个赞、转发、在看三连吧感谢感谢。那我们下次再见。您的一键三连是我更新的最大动力谢谢山水有相逢来日皆可期谢谢阅读我们再会我手中的金箍棒上能通天下能探海

相关新闻

书匠策AI:毕业论文“智造”新引擎,开启高效写作新纪元!

书匠策AI:毕业论文“智造”新引擎,开启高效写作新纪元!

在学术的浩瀚星空中,毕业论文无疑是那颗最耀眼的星辰,它汇聚了学子们多年的智慧与汗水,是通往学术巅峰的必经之路。然而,面对这颗星辰的攀登之路,许多学子却常常感到力不从心,从选题到结构,从语…

2026/7/3 16:25:19 阅读更多 →
2025年年度终结之12.战略之根基

2025年年度终结之12.战略之根基

蒙古草原上以前处理有关争议时,采用的是长期以来形成的自然法,由于没有文字,这种法令条款只能靠口授相传,简略粗疏。成吉思汗宣布建立大蒙古国之后,塔塔统阿参照畏吾儿文,创立了蒙古文字。有了文字后&#…

2026/7/6 18:16:13 阅读更多 →
2026年2月亲测:合肥门窗品牌服务实录

2026年2月亲测:合肥门窗品牌服务实录

行业痛点分析当前,合肥乃至全国的高端家装门窗市场正面临着一系列严峻的技术与服务挑战。这些挑战不仅关乎产品的物理性能,更直接影响到最终用户的居住体验与长期价值。在技术层面,型材结构强度不足、玻璃系统性能不稳定、五金配件耐久性差以…

2026/7/6 20:46:31 阅读更多 →

最新新闻

Python OpenCV 图像识别:QQ三国华容道5阶拼图自动化脚本开发指南

Python OpenCV 图像识别:QQ三国华容道5阶拼图自动化脚本开发指南

Python OpenCV 图像识别:QQ三国华容道5阶拼图自动化脚本开发指南1. 游戏窗口定位与图像采集开发自动化脚本的第一步是准确捕获游戏窗口内容。这里我们使用PyWin32库实现窗口定位,配合OpenCV进行图像采集:import win32gui import numpy as np …

2026/7/6 22:31:22 阅读更多 →
CVPR/ICCV/ECCV 2024-2025 投稿日历:3大顶会截稿与会议时间全解析

CVPR/ICCV/ECCV 2024-2025 投稿日历:3大顶会截稿与会议时间全解析

CVPR/ICCV/ECCV 2024-2025 投稿日历:3大顶会截稿与会议时间全解析计算机视觉领域的三大顶级会议CVPR、ICCV和ECCV,被研究者们亲切地称为"ICE"会议。对于准备投稿的研究生和初级研究人员来说,掌握这些会议的投稿时间节点和会议周期规…

2026/7/6 22:31:22 阅读更多 →
SPI EEPROM与Cortex-M4的高可靠性嵌入式存储方案

SPI EEPROM与Cortex-M4的高可靠性嵌入式存储方案

1. 项目背景与核心需求在嵌入式系统设计中,数据存储的可靠性始终是开发者面临的关键挑战之一。当系统意外断电或发生故障时,如何确保关键数据不丢失?这正是非易失性存储技术要解决的核心问题。M95M02-DR作为意法半导体(ST)推出的2Mb SPI EEPR…

2026/7/6 22:29:21 阅读更多 →
嵌入式系统电源管理:TPS65263与PIC32MZ实战设计

嵌入式系统电源管理:TPS65263与PIC32MZ实战设计

1. 项目背景与核心需求在嵌入式系统开发中,电源管理一直是个关键挑战。随着现代MCU和外设的复杂度提升,单一电压轨已经无法满足需求。我最近在为一个工业传感器项目设计供电方案时,就遇到了需要同时提供1.8V、3.3V和5V三种电压的棘手情况。传…

2026/7/6 22:25:18 阅读更多 →
海康威视 SDK V6.1.4.7 Java 二次开发:SpringBoot 集成 3 大核心功能(预览/回放/云台)

海康威视 SDK V6.1.4.7 Java 二次开发:SpringBoot 集成 3 大核心功能(预览/回放/云台)

海康威视SDK V6.1.4.7 Java二次开发:SpringBoot集成3大核心功能实战指南在智能安防领域,海康威视设备占据着重要市场份额。本文将带您从零开始构建一个基于SpringBoot的企业级视频监控管理系统,实现设备实时预览、录像回放和云台控制三大核心…

2026/7/6 22:25:18 阅读更多 →
如何快速获取音乐歌词:一站式歌词下载解决方案

如何快速获取音乐歌词:一站式歌词下载解决方案

如何快速获取音乐歌词:一站式歌词下载解决方案 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 还在为找不到音乐歌词而烦恼吗?163MusicLyrics是一…

2026/7/6 22:21:04 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻