Java-155 MongoDB Spring Boot 连接实战 | Template vs Repository(含索引与常见坑)

TL;DR

场景:Spring Boot 连接 MongoDB,Template/Repository 两种姿势。
结论:5 分钟跑通;含 MRE、索引与常见坑。
产出:application.yaml、实体/Repo/模板示例、集成测试样例。

快速启动MongoDB开发环境

如果你还没有MongoDB的开发环境,可以使用Docker在本地快速部署一个独立运行的MongoDB实例。这种方式特别适合开发测试场景,能够免除复杂的安装配置过程。

使用Docker Compose启动MongoDB

我们推荐使用Docker Compose来管理容器化部署,下面是一个完整的compose.yaml配置文件:

yaml 复制代码
# compose.yaml
version: '3.8'  # 指定Compose文件格式版本

services:
  mongo:
    image: mongo:7  # 使用官方MongoDB 7.0版本的镜像
    container_name: mongodb-container  # 为容器指定名称
    ports:
      - "37017:27017"  # 将容器内部的27017端口映射到主机的37017端口
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin  # 设置管理员用户名
      - MONGO_INITDB_ROOT_PASSWORD=admin123  # 设置管理员密码
    volumes:
      - mongo_data:/data/db  # 持久化数据存储

volumes:
  mongo_data:  # 声明数据卷,确保数据持久化

启动步骤

  1. 将上述内容保存为compose.yaml文件
  2. 打开终端,导航到文件所在目录
  3. 执行命令:docker-compose up -d

启动命令与连接:

shell 复制代码
docker compose up -d
export MONGODB_URI='mongodb://admin:admin123@localhost:37017/wzk_test?authSource=admin'

连接说明

启动成功后,你可以通过以下方式连接MongoDB:

  • 连接字符串:mongodb://admin:admin123@localhost:37017
  • 使用MongoDB Compass等GUI工具连接
  • 通过命令行工具:mongo --port 37017 -u admin -p admin123 --authenticationDatabase admin

此配置提供了一个安全的基础环境,包含了:

  • 最新的MongoDB 7.0版本
  • 预设的管理员账户
  • 数据持久化存储
  • 端口映射避免与本地可能已安装的MongoDB冲突

Spring Boot 访问

Template方式

Maven

xml 复制代码
 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.2.RELEASE</version>
</parent>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

对应的内容如下所示:

修改配置

yaml 复制代码
spring:
  data:
    mongodb:
      uri: mongodb://admin:admin123@localhost:37017/wzk_test?authSource=admin

在生产环境中,可以使用环境变量的方式:

yaml 复制代码
spring:
  data:
    mongodb:
      uri: ${MONGODB_URI:mongodb://admin:admin123@localhost:37017/wzk_test?authSource=admin}

DAO

java 复制代码
@Autowired
private MongoTemplate mongoTemplate;

编写代码

java 复制代码
// 使用了 Lombok
@Component
@RequiredArgsConstructor
public class WzkDao {
    private final MongoTemplate mongo;

    public List<WzkDocument> findAdults() {
        Query q = new Query(Criteria.where("age").gte(18));
        return mongo.find(q, WzkDocument.class);
    }
}

Repository方式

编写实体

在实体类上

java 复制代码
@Document("集合名")

比如我们写一个类:

java 复制代码
package icu.wzk.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

// 可以使用 Lombok
@Document("wzk_document")
public class WzkDocument {
    @Id
    private String id;

    @Indexed // 如 name 需要频繁查询,建议建索引;唯一可用 unique = true
    private String name;
    private Integer age;
    // getter/setter/构造略
}

对应的截图如下所示:

继承类

java 复制代码
package icu.wzk.dao;

import icu.wzk.model.WzkDocument;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface WzkDocumentRepo extends MongoRepository<WzkDocument, String> {
    WzkDocument findByName(String name);
}

我们可以通过如下的方式使用,这里就不过多进行介绍了:

java 复制代码
package icu.wzk;


import icu.wzk.dao.WzkDocumentRepo;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
@RequiredArgsConstructor
public class WzkStartApp {

    public static void main(String[] args) {
        SpringApplication.run(WzkStartApp.class, args);
    }

    private final WzkDocumentRepo wzkDocumentRepo;


}

问题快速排查

症状与排查修复表

症状 根因 快排查方法 修复方法
启动连不上 URI/端口/库名/鉴权写错 mongo --host localhost --port 37017 修正 spring.data.mongodb.uri
Repo 报空指针 实体无 @Id/泛型不匹配 看实体与泛型 @Id,泛型对齐
查慢 无索引/条件不命中 explain()totalDocsExamined 加索引或改查询
事务失败 单机非副本集 rs.status() 改为副本集/Testcontainers 配置
凭证泄漏 URI 写在仓库 看配置 ${MONGODB_URI:...} 环境变量

【知识补充】Template方式详解

1. 概念与原理

Template(模板)是一种设计模式,它通过定义算法的骨架来规范流程,同时允许子类在不改变算法结构的情况下重新定义某些步骤。这种模式属于行为型设计模式,主要用于解决在多个相似流程中重复代码的问题。

核心原理:

  • 父类定义算法框架(不可变部分)
  • 子类实现具体步骤(可变部分)
  • 通过抽象方法或钩子方法实现扩展点

2. 实现方式

2.1 类实现方式

java 复制代码
public abstract class AbstractTemplate {
    // 模板方法(final防止子类修改算法结构)
    public final void templateMethod() {
        step1();
        step2();
        if(hookMethod()) {
            step3();
        }
    }
    
    // 基本方法(抽象方法由子类实现)
    protected abstract void step1();
    protected abstract void step2();
    
    // 钩子方法(提供默认实现)
    protected boolean hookMethod() {
        return true;
    }
    
    // 具体方法(通用实现)
    private void step3() {
        System.out.println("执行步骤3");
    }
}

2.2 接口默认方法实现(Java 8+)

java 复制代码
public interface Template {
    default void templateMethod() {
        step1();
        step2();
        if(hookMethod()) {
            step3();
        }
    }
    
    void step1();
    void step2();
    
    default boolean hookMethod() {
        return true;
    }
    
    private void step3() {
        System.out.println("执行步骤3");
    }
}

3. 应用场景

3.1 典型应用

  1. 框架设计:如Spring的JdbcTemplate
  2. 业务流程:如订单处理流程
  3. 算法实现:如排序算法模板
  4. 文档生成:如报告生成器

3.2 具体示例

电商订单处理模板

java 复制代码
public abstract class OrderProcessor {
    public final void processOrder() {
        validateOrder();
        calculatePayment();
        if(needsShipping()) {
            arrangeShipping();
        }
        sendConfirmation();
    }
    
    protected abstract void validateOrder();
    protected abstract void calculatePayment();
    protected boolean needsShipping() {
        return true;
    }
    private void arrangeShipping() {
        // 物流安排实现
    }
    private void sendConfirmation() {
        // 发送确认邮件/短信
    }
}

4. 优缺点分析

优点:

  1. 代码复用:将不变行为搬到父类,避免重复代码
  2. 扩展性好:通过子类扩展新的行为,符合开闭原则
  3. 便于维护:算法结构清晰,修改只需调整模板方法
  4. 控制反转:由父类控制流程,子类只需关注实现细节

缺点:

  1. 类数量增加:每个具体实现都需要一个子类
  2. 设计复杂度:需要合理划分可变和不可变部分
  3. 继承限制:Java单继承机制会限制使用场景

5. 最佳实践

  1. 合理使用钩子方法:为可选步骤提供灵活的扩展点
  2. 控制模板方法复杂度:避免创建过于复杂的模板方法
  3. 命名规范
    • 模板方法使用"template"前缀
    • 钩子方法使用"hook"或"can"前缀
  4. 文档说明:明确标注哪些方法是必须实现的,哪些是可选的

6. 与其他模式的关系

  1. 与策略模式

    • Template使用继承
    • Strategy使用组合
    • Template强调算法步骤,Strategy强调算法替换
  2. 与工厂方法模式

    • 工厂方法常作为模板方法的一步实现
  3. 与建造者模式

    • 都用于分步构建对象
    • Template强调步骤顺序,Builder强调创建过程

7. 扩展应用

7.1 回调方式的模板模式

java 复制代码
public class TemplateWithCallback {
    public void execute(Callback callback) {
        preProcess();
        callback.doOperation();
        postProcess();
    }
    
    private void preProcess() {
        // 预处理逻辑
    }
    
    private void postProcess() {
        // 后处理逻辑
    }
    
    public interface Callback {
        void doOperation();
    }
}

7.2 函数式编程实现

java 复制代码
public class FunctionalTemplate {
    public void execute(Runnable preProcess,
                       Runnable operation,
                       Runnable postProcess) {
        preProcess.run();
        operation.run();
        postProcess.run();
    }
}

其他系列

🚀 AI篇持续更新中(长期更新)

AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南!
AI-调查研究-108-具身智能 机器人模型训练全流程详解:从预训练到强化学习与人类反馈
🔗 AI模块直达链接

💻 Java篇持续更新中(长期更新)

Java-154 深入浅出 MongoDB 用Java访问 MongoDB 数据库 从环境搭建到CRUD完整示例

MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!
🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
🔗 大数据模块直达链接

相关推荐
武子康4 小时前
Java-157 MongoDB 存储引擎 WiredTiger vs InMemory:何时用、怎么配、如何验证 mongod.conf
java·数据库·sql·mongodb·性能优化·系统架构·nosql
br456vv4 小时前
Adobe Dimension 2025 (3D可视化设计神器) 解锁版
java·adobe·工具
野犬寒鸦4 小时前
从零起步学习MySQL || 第八章:索引深入理解及高级运用(结合常见优化问题讲解)
java·服务器·数据库·后端·mysql
疯狂踩坑人4 小时前
【深入浅出Nodejs】异步非阻塞IO
后端·node.js
奥尔特星云大使4 小时前
Docker 拉取 MySQL 5.7 镜像、启动容器并进入 MySQL
数据库·mysql·docker·容器
赵杰伦cpp4 小时前
C++的继承机制精讲
java·开发语言·c++·后端
aloha_5 小时前
LLM模型指令遵循偏差
后端
.ZGR.5 小时前
蓝桥杯高校新生编程赛第一场题解——Java
java·算法·蓝桥杯
gongzemin5 小时前
使用阿里云ECS部署Express
后端·node.js·express