生产级spring boot + mongodb必须规避默认陷阱:禁用无索引查询与findall(),分页改用游标而非skip/limit,事务需副本集支持并显式配置超时,索引须按等值在前范围在后原则设计,且所有更新操作必须原子化、字段级精确控制。

生产级 CRUD 不是“能跑就行”,而是要扛住并发、容错、可观测和可维护。Spring Boot + MongoDB 的组合在真实业务中,最常翻车的不是语法错误,而是默认配置没调、事务没开、索引没建、异常没兜底。
如何用 MongoRepository 实现安全高效的查询
MongoRepository 看似省事,但直接调用 findAll() 或 findByXxx() 在生产环境极易引发全表扫描或内存溢出。
- 必须显式加
@Query并配合@Indexed字段——比如模糊搜索标题,别只写findByNameContaining(String name),得确保name字段有@TextIndexed或复合索引 - 分页必须用
Pageable,且禁用findAll(Pageable)以外的无限制查询;MongoDB 的skip/limit在大数据量下性能陡降,超 10 万文档建议改用游标(find+sort+_id范围查询) - 避免返回整个文档:用
@Aggregation投影必要字段,或定义 DTO 接口(如interface ArticleSummary { String getId(); String getTitle(); }),Spring Data 会自动映射
MongoTemplate 执行原子更新与条件删除时的关键约束
当业务逻辑涉及“先查再改”或“多字段联合判断删除”,MongoTemplate 是唯一可靠选择,但默认行为不保证原子性。
-
updateFirst()和remove()的Query必须包含完整匹配条件,否则可能误删/误改——例如删除草稿,不能只靠status = "draft",还得加userId防越权 - 更新操作务必使用
Update.update()显式指定字段,禁用set()全量覆盖,否则会清空未传字段(如用户资料更新漏传avatarUrl,该字段变null) - 高并发场景下,用
findAndModify()替代 “查-改-存” 三步,它底层调用 MongoDB 的findAndModify命令,天然原子;但注意它不支持数组字段的 $push/$pull 复合操作,需拆成两步并加版本号校验
事务开启后仍失败的三个典型原因
MongoDB 4.0+ 支持副本集事务,但 Spring Boot 默认不启用,且启用后仍有隐藏陷阱。
- 事务只能在副本集(Replica Set)上运行,单节点
mongod启动无效;连接字符串必须含?replicaSet=rs0,且应用配置里要加spring.data.mongodb.grid-fs.enabled=false(GridFS 不支持事务) - 事务内所有操作必须指向同一数据库,跨库操作(如日志库 + 主业务库)会直接抛
MongoCommandException: Transaction numbers do not match - 事务超时默认 60 秒,长耗时操作(如批量导入)必须显式设置:
@Transactional(timeout = 300),否则中途卡住会静默回滚
索引缺失导致的慢查询如何快速定位
线上慢查询往往不是代码问题,而是索引没跟上数据模型演进。
- 开启 MongoDB 慢日志:
db.setProfilingLevel(1, { slowms: 100 }),然后查db.system.profile.find({ millis: { $gt: 100 } }),重点关注executionStats.executionStages.stage === "COLLSCAN" - 复合索引顺序很重要:等值查询字段放前,范围查询(
$gt/$regex)放后;比如查询{ status: "published", createdAt: { $gte: ... } },索引应为{ status: 1, createdAt: 1 },反过来就失效 - 文本索引(
@TextIndexed)不支持排序,全文搜索后想按时间倒序,必须额外建{ status: 1, createdAt: -1 }索引,并在查询时用$text+$sort分开处理
真正卡住团队的,从来不是“怎么写 CRUD”,而是“为什么这个查询突然变慢”“为什么并发一高就丢数据”“为什么事务日志里全是 timeout”。这些点不提前压测、不看 Profiling 日志、不核对副本集状态,上线当天就会出事。











