Java高级全套教程(六)—— MongoDB超详细实战详解
Java高级全套教程(六)—— MongoDB超详细实战详解
一、非关系型数据库概述与MongoDB核心定位
1.1 传统关系型数据库的生产痛点
在互联网高速迭代的业务场景中,MySQL、Oracle等传统关系型数据库(RDBMS)凭借事务一致性、结构化存储的优势,长期占据企业数据存储主流场景。但随着海量用户、高并发读写、动态数据模型、海量非结构化数据场景的普及,关系型数据库的架构短板逐渐凸显,无法适配多元化的互联网业务需求。
其核心痛点主要集中在四大维度:
-
数据模型固化:关系型数据库依赖固定表结构,字段、类型、关联关系创建后难以灵活修改,面对需求频繁迭代的互联网项目,数据表变更成本极高,极易引发业务兼容问题。
-
高并发读写瓶颈:传统数据库依赖磁盘IO、事务锁机制,在万级以上QPS的高并发读写场景中,锁竞争、磁盘读写延迟会严重拖慢系统响应速度,性能优化难度大。
-
非结构化数据适配差:对于用户画像、设备日志、社交动态、地理位置信息等非结构化、半结构化数据,无法高效存储,通常需要拆表、冗余存储,导致表结构臃肿、查询效率低下。
-
横向扩容成本高:关系型数据库的主从复制、分库分表架构复杂,扩容需要迁移数据、修改配置、适配路由,无法实现无感弹性扩容,难以支撑业务爆发式增长。
1.2 NoSQL数据库分类与适用场景
NoSQL(Not Only SQL)即非关系型数据库,是为解决传统RDBMS短板而生的分布式数据存储方案,摒弃了固定表结构、事务强一致性、主外键关联特性,以高并发、高可用、高伸缩、灵活数据模型为核心优势,主打最终一致性,适配互联网海量数据场景。主流NoSQL数据库分为四大类:
-
键值型(Key-Value):代表产品Redis、Memcached,数据以键值对存储,读写速度极快,主要用于缓存、秒杀、会话存储场景。
-
文档型(Document):代表产品MongoDB、CouchDB,数据以类JSON文档存储,结构灵活,适配动态数据模型、海量非结构化数据场景。
-
列存储型(Column):代表产品HBase、Cassandra,以列为单位存储数据,适合海量日志、大数据离线分析场景。
-
图数据库(Graph):代表产品Neo4j,专注于节点与关系存储,适配社交关系、知识图谱、推荐算法场景。
1.3 MongoDB简介与核心优势
MongoDB是一款开源、跨平台、高性能、无模式的文档型NoSQL数据库,由10gen公司开发,命名源自humongous(海量的、巨大的),主打海量数据存储与高并发读写场景。MongoDB摒弃了复杂的事务和固定结构,以BSON二进制文档为核心存储单元,完美适配互联网动态业务场景,是中小企业非结构化数据存储的首选方案。
相较于传统数据库及其他NoSQL数据库,MongoDB核心优势极为突出:
-
无模式灵活存储:集合无需固定结构,不同文档可拥有不同字段、不同数据类型,支持动态增删改字段,适配需求快速迭代的项目。
-
类JSON嵌套结构:支持文档嵌套、数组存储,可将关系型数据库多表关联数据整合为单文档,彻底规避多表JOIN查询的性能损耗。
-
超高读写性能:基于内存映射文件机制,大部分热点数据读写走内存,支持万级QPS,远超传统关系型数据库。
-
无感弹性扩容:支持分片集群横向扩容,无需停机、无需迁移数据,可按需扩容节点,适配海量数据增长。
-
高可用容灾机制:支持副本集多节点备份,自动故障转移,单节点宕机不影响整体服务,保障数据安全与服务稳定性。
-
丰富的索引与查询能力:支持单键、复合、地理空间、全文、哈希等多种索引,查询语法接近SQL,学习成本低。
-
完善的生态适配:完美适配Java、Python、Go等主流开发语言,支持SpringBoot快速集成,运维工具丰富,落地成本低。
1.4 MongoDB企业级适用场景与选型标准
1.4.1 核心适用场景
-
互联网网站业务:适配用户信息、用户画像、文章评论、朋友圈动态等实时读写场景,支持高并发插入、更新、查询,具备完善的集群伸缩能力。
-
海量日志存储:存储物联网设备日志、系统操作日志、用户行为日志,支持海量低价值数据的高效写入与多维度分析。
-
缓存中间层:可作为持久化缓存层,弥补Redis内存缓存断电丢失的短板,系统重启后可快速恢复缓存数据,避免底层数据源压力过载。
-
地理位置服务:依托地理空间索引,实现附近的人、附近门店、轨迹定位等功能,广泛应用于外卖、打车、社交、物流场景。
-
动态表单业务:电商商品参数、自定义表单、企业审批流程等动态字段业务,无需频繁修改数据表,适配多变的业务模型。
-
游戏业务:存储游戏用户角色、装备、积分、战绩等信息,通过嵌套文档一站式存储关联数据,查询更新效率极高。
1.4.2 选型判定标准
满足以下任意2项及以上条件,优先选择MongoDB,可最大化发挥其性能优势:
-
业务无需复杂事务、跨表JOIN关联,仅需单文档数据一致性;
-
项目处于快速迭代阶段,数据模型不固定,需要频繁调整字段结构;
-
业务读写QPS高达2000+,需要支撑高并发实时读写;
-
数据量级达TB/PB级别,需要低成本海量数据存储方案;
-
业务增长迅速,需要数据库支持快速横向扩容;
-
需要大量地理位置查询、全文模糊检索、数组维度查询场景;
-
业务要求99.999%高可用,需要自动故障转移、数据多副本容灾。
二、MongoDB核心数据模型与底层原理
2.1 MongoDB与关系型数据库映射关系
MongoDB的逻辑架构与MySQL高度相似,核心概念可一一对应,降低开发者学习门槛,二者核心映射关系如下:
| 关系型数据库(RDBMS) | MongoDB | 核心说明 |
|---|---|---|
| 数据库(Database) | 数据库(Database) | 独立的数据存储单元,相互隔离 |
| 数据表(Table) | 集合(Collection) | 存储一组同类文档,无固定结构约束 |
| 数据行(Row) | 文档(Document) | 最小数据存储单元,BSON格式 |
| 数据列(Column) | 字段(Field) | 文档中的单个键值对,无固定类型约束 |
| 主键(Primary Key) | _id字段 | 文档唯一标识,自动生成全局唯一值 |
| 索引(Index) | 索引(Index) | 支持多类型索引,优化查询性能 |
| JOIN关联查询 | 嵌套文档/引用关联 | 通过嵌套替代多表关联,提升查询效率 |
2.2 BSON数据格式详解
MongoDB所有数据均以**BSON(Binary JSON)**二进制格式存储,是JSON的超集,保留了JSON轻量、易解析的特性,同时拓展了更多专业数据类型,适配数据库持久化存储场景。BSON核心特性为:轻量性、可遍历性、高效性,读写效率远高于普通JSON格式。
MongoDB文档支持的全量数据类型及实操示例如下,覆盖企业开发所有常用场景:
| 数据类型 | 类型说明 | 实操示例 |
|---|---|---|
| String | 字符串类型,最常用数据类型 | {username: “zhangsan”, gender: “male”} |
| Int32/Int64 | 32位/64位整型数值 | {age: 25, score: 98} |
| Double | 双精度浮点型,存储小数 | {height: 175.5, weight: 65.2} |
| Boolean | 布尔类型,true/false | {isVip: true, isDelete: false} |
| ObjectId | 文档唯一ID,系统自动生成 | {_id: ObjectId(“62a00e5c1eb2c6ab85dd5eec”)} |
| Array | 数组类型,存储多个同/异类数据 | {hobbies: [“跑步”, “阅读”, “编程”], tags: [1,2,3]} |
| Embedded Document | 内嵌文档,实现数据嵌套 | {address: {province: “广东”, city: “深圳”}} |
| Date | 标准日期时间类型 | {createTime: new Date(), birthday: ISODate(“1999-01-01”)} |
| Null | 空值类型 | {remark: null} |
| Binary | 二进制数据,存储图片、文件流 | {fileData: BinData(0, “xxxxxx”)} |
| Timestamp | 时间戳,用于数据版本控制 | {updateTs: new Timestamp()} |
2.3 数据模型设计:内嵌与引用选型
MongoDB无主外键关联机制,通过内嵌文档和引用关联两种方式实现数据关联,合理选择数据模型是提升查询性能的核心,需根据业务关系灵活选型。
2.3.1 内嵌文档模型
将关联数据直接嵌套在主文档内部,数据集中存储,一次查询即可获取所有关联数据,无多表查询开销,是MongoDB推荐的优先选型方案。
适用场景:一对一、一对多关联关系;数据需要频繁联合查询;子数据不会独立频繁修改;数据嵌套层级可控。
实战案例(用户内嵌地址、爱好信息):
{
"_id": ObjectId("65001234567890abcdef1234"),
"username": "lisi",
"age": 28,
"isVip": true,
"hobbies": ["游泳", "骑行", "摄影"],
"address": {
"province": "浙江省",
"city": "杭州市",
"district": "西湖区"
},
"createTime": ISODate("2025-01-01T10:00:00Z")
}
2.3.2 引用关联模型
将关联数据单独存储为独立文档,通过存储对方文档的_id实现关联,类似关系型数据库的外键,避免数据冗余,适合复杂关联场景。
适用场景:多对多复杂关联;子数据频繁独立修改;内嵌会导致数据严重冗余;嵌套层级过深的大数据集。
实战案例(用户与订单引用关联):
// 用户主文档
{
"_id": ObjectId("65001234567890abcdef1234"),
"username": "lisi",
"age": 28,
"orderIds": [
ObjectId("65001234567890abcdef1235"),
ObjectId("65001234567890abcdef1236")
]
}
// 独立订单文档
{
"_id": ObjectId("65001234567890abcdef1235"),
"orderNo": "ORD20250526001",
"amount": 299.9,
"status": "已完成",
"userId": ObjectId("65001234567890abcdef1234")
}
三、MongoDB存储引擎深度解析
存储引擎是MongoDB的核心底层组件,负责管理数据在内存和磁盘的存储、读写、缓存、持久化逻辑,直接决定数据库的性能、并发能力、数据可靠性。MongoDB支持多款存储引擎,不同引擎适配不同业务场景。
3.1 WiredTiger存储引擎(默认)
WiredTiger是MongoDB 3.2及以上版本的默认存储引擎,完全替代了老旧的MMAPv1引擎,主打高并发、高压缩、低资源占用,适配99%的企业生产场景。
3.1.1 核心核心特性
-
文档级并发控制:支持单文档粒度的读写锁,多客户端可同时修改同一集合的不同文档,彻底解决旧引擎集合级锁的并发瓶颈,高并发性能大幅提升。
-
MVCC多版本并发控制:读写操作互不阻塞,读操作读取数据快照,写操作独立执行,无读写锁竞争,保障高并发场景下的响应速度。
-
自动数据压缩:默认对集合数据开启块压缩、对索引开启前缀压缩,以少量CPU开销换取极高的磁盘利用率,可节省30%-80%磁盘空间。
-
快照与检查点机制:每60秒自动生成数据检查点,将内存快照持久化到磁盘,保证数据一致性,宕机后可通过日志快速恢复数据。
-
完善的日志持久化:通过WAL预写日志记录所有数据修改操作,检查点之间的增量修改可通过日志回放恢复,彻底避免数据丢失。
3.1.2 内存缓存机制
WiredTiger的内存缓存大小自动适配服务器配置,默认取值规则为:取(物理内存-1GB)的50% 和 256MB 中的较大值,最大化利用内存提升热点数据读写速度。
示例:服务器内存1.25GB时,缓存大小为256MB;服务器内存16GB时,缓存大小为7.5GB。
3.2 In-Memory内存存储引擎
In-Memory是MongoDB企业版专属的内存存储引擎,所有业务数据仅存储在内存中,不持久化到磁盘,读写速度达到极致,仅适配超高并发、对数据持久化要求低的临时业务场景。
3.2.1 核心特性
-
纯内存读写:无磁盘IO开销,读写性能远超WiredTiger,支撑十万级超高并发。
-
文档级并发锁:同样支持多客户端并发修改不同文档,并发能力优异。
-
无持久化能力:服务器重启、宕机后,所有业务数据全部丢失,仅保留少量元数据、索引临时文件。
3.2.2 自定义内存配置
默认占用50%物理内存,可通过配置文件手动指定内存大小,避免内存溢出:
storage:
engine: inMemory
dbPath: /data/mongodb/inmem
inMemory:
engineConfig:
inMemorySizeGB: 4 # 限定内存占用4GB
四、MongoDB生产级环境搭建(双方式部署)
本文提供YUM源码部署和Docker容器部署两种生产级方案,YUM部署适合物理机长期运维,Docker部署适合快速搭建、环境隔离、云服务器场景。
4.1 YUM方式部署MongoDB(CentOS7)
4.1.1 配置阿里云YUM源
官方源下载速度缓慢,采用阿里云镜像源提升部署速度,进入YUM配置目录,创建MongoDB专属源文件:
# 进入yum源配置目录
cd /etc/yum.repos.d
# 创建mongodb镜像源文件
vim mongodb-org-5.0.repo
写入以下镜像源配置内容:
[mongodb-org]
name=MongoDB Repository
baseurl=http://mirrors.aliyun.com/mongodb/yum/redhat/7Server/mongodb-org/5.0/x86_64/
gpgcheck=0
enabled=1
4.1.2 执行安装与环境初始化
# 更新yum缓存
yum update -y
# 安装MongoDB5.0版本全套组件
yum install -y mongodb-org
# 查看安装目录
whereis mongod
4.1.3 核心配置文件修改
编辑主配置文件,开启远程连接、优化性能参数:
vim /etc/mongod.conf
修改核心配置项:
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
storage:
dbPath: /var/lib/mongo
journal:
enabled: true
net:
port: 27017
bindIp: 0.0.0.0 # 允许所有IP远程连接,关闭仅本地访问
processManagement:
fork: true # 后台运行
security:
authorization: disabled # 初始关闭认证,后续按需开启
4.1.4 服务启停与开机自启
# 启动服务
systemctl start mongod.service
# 停止服务
systemctl stop mongod.service
# 重启服务
systemctl restart mongod.service
# 查看运行状态
systemctl status mongod.service
# 设置开机自启
systemctl enable mongod.service
4.2 Docker方式快速部署MongoDB
Docker部署无需复杂配置,环境隔离、一键搭建,适合测试、快速落地场景,默认部署5.0.9稳定版。
4.2.1 拉取镜像与创建挂载目录
# 拉取MongoDB镜像
docker pull mongo:5.0.9-focal
# 查看已下载镜像
docker images | grep mongo
# 创建数据持久化挂载目录
mkdir -p /mnt/mongodb/data /mnt/mongodb/log
4.2.2 启动容器服务
docker run -itd \
--privileged=true \
--name mongo5 \
-p 27017:27017 \
-v /mnt/mongodb/data:/data/db \
-v /mnt/mongodb/log:/var/log/mongodb \
--restart always \
mongo:5.0.9-focal
参数说明:端口映射27017(MongoDB默认端口)、数据日志持久化、开机自启、超级权限运行。
4.3 客户端连接测试
支持两种连接方式:命令行Shell连接、可视化工具连接,生产环境推荐使用NosqlBooster可视化工具,操作便捷。
# 本地shell直接连接
mongo
# 指定IP端口远程连接
mongo --host 127.0.0.1 --port 27017
五、MongoDB核心命令实操(CRUD+聚合+索引)
本章讲解企业开发高频核心命令,摒弃基础冗余语法,聚焦生产常用操作,附带完整实操案例与参数说明。
5.1 基础库与集合操作命令
# 1.查看所有数据库
show dbs
# 2.切换/创建数据库(不存在则自动创建)
use business_db
# 3.查看当前所在数据库
db
# 4.创建自定义集合
db.createCollection("user_info")
db.createCollection("order_list")
# 5.查看当前数据库所有集合
show collections
show tables
# 6.删除指定集合
db.user_info.drop()
# 7.删除当前整个数据库
db.dropDatabase()
5.2 文档CRUD增删改查实操
5.2.1 新增文档操作
集合不存在则自动创建,不指定_id时系统自动生成唯一ObjectId,支持单条、批量新增。
# 单条文档新增
db.user_info.insertOne({
username: "wangwu",
age: 26,
gender: "male",
isVip: false,
score: 88.5,
hobbies: ["篮球", "健身"],
createTime: new Date()
})
# 批量文档新增
db.user_info.insertMany([
{username: "zhaoliu", age: 29, gender: "female", isVip: true, score: 92.0, createTime: new Date()},
{username: "tianqi", age: 24, gender: "male", isVip: true, score: 79.0, createTime: new Date()},
{username: "luba", age: 30, gender: "female", isVip: false, score: 85.5, createTime: new Date()}
])
5.2.2 文档查询操作(高频)
支持全量查询、条件查询、比较查询、复合查询、排序分页,覆盖所有业务查询场景。
# 1.查询集合所有文档
db.user_info.find({})
# 2.条件精准查询(用户名匹配)
db.user_info.find({username: "wangwu"})
# 3.比较查询(年龄大于25岁)
db.user_info.find({age: {$gt: 25}})
# 4.复合条件查询(25-30岁的VIP用户)
db.user_info.find({
age: {$gte:25, $lte:30},
isVip: true
})
# 5.内嵌字段查询
db.user_info.find({"address.city": "深圳市"})
# 6.排序查询(按分数降序,年龄升序)
db.user_info.find({}).sort({score:-1, age:1})
# 7.分页查询(第1页,每页2条数据)
db.user_info.find({}).skip(0).limit(2)
# 8.只查询指定字段(只展示用户名、年龄)
db.user_info.find({}, {username:1, age:1, _id:0})
5.2.3 文档更新操作
支持单条更新、批量更新、字段新增、时间戳自动更新,规避全文档覆盖更新风险。
# 单条更新:修改指定用户分数,新增更新时间字段
db.user_info.updateOne(
{username: "wangwu"},
{
$set: {score: 90.0, gender: "male"},
$currentDate: {updateTime: true}
}
)
# 批量更新:所有非VIP用户统一加分
db.user_info.updateMany(
{isVip: false},
{$inc: {score: 5.0}}
)
# 文档整体替换
db.user_info.replaceOne(
{username: "luba"},
{username: "luba", age: 31, isVip: true, score: 90.5, updateTime: new Date()}
)
5.2.4 文档删除操作
# 删除单条指定条件文档
db.user_info.deleteOne({username: "tianqi"})
# 批量删除指定条件文档
db.user_info.deleteMany({isVip: false})
# 清空集合所有文档(保留集合结构)
db.user_info.deleteMany({})
5.3 聚合管道高阶实操
聚合管道是MongoDB数据分析核心能力,通过多阶段流水线处理数据,实现分组统计、求和、平均值、排序筛选等复杂业务逻辑。
5.3.1 基础聚合统计
基于订单数据,实现按订单状态分组、统计订单数量、总金额、平均单价。
# 插入测试订单数据
db.order_list.insertMany([
{orderNo:"ORD001", price:199, num:2, status:"已完成", createDate:ISODate("2025-05-01")},
{orderNo:"ORD002", price:299, num:1, status:"待付款", createDate:ISODate("2025-05-02")},
{orderNo:"ORD003", price:199, num:3, status:"已完成", createDate:ISODate("2025-05-03")},
{orderNo:"ORD004", price:399, num:1, status:"已发货", createDate:ISODate("2025-05-04")},
{orderNo:"ORD005", price:299, num:2, status:"待付款", createDate:ISODate("2025-05-05")}
])
# 聚合统计:按订单状态分组,统计订单数、总销售额、平均购买数量
db.order_list.aggregate([
{$match: {createDate: {$gte: ISODate("2025-05-01")}}}, // 时间筛选
{$group: {
_id: "$status",
totalOrder: {$sum: 1}, // 订单总数
totalAmount: {$sum: {$multiply: ["$price", "$num"]}}, // 总金额
avgNum: {$avg: "$num"} // 平均购买数量
}},
{$sort: {totalAmount: -1}} // 按总金额倒序
])
5.3.2 聚合管道优化规则
-
优先使用$match前置过滤数据,减少后续管道处理的数据量,大幅提升性能;
-
project、project、project、addFields后置执行,避免无效字段计算;
-
单管道阶段数量不超过1000个,结果集大小不超过16MB,超大结果需分页处理。
5.4 全类型索引实操与优化
索引是数据库查询优化的核心,无索引查询会触发全表扫描,数据量越大性能差距越明显。MongoDB默认对_id字段创建唯一索引,支持多类型自定义索引。
5.4.1 单键索引
# 对用户年龄创建升序索引
db.user_info.createIndex({age:1})
# 对内嵌字段创建索引
db.user_info.createIndex({"address.city":1})
5.4.2 复合索引
# 联合索引:年龄+VIP状态
db.user_info.createIndex({age:1, isVip:-1})
5.4.3 多键索引(数组专用)
# 对爱好数组创建多键索引,优化数组查询
db.user_info.createIndex({hobbies:1})
5.4.4 地理空间索引(实战常用)
# 插入地理位置数据
db.store_info.insertOne({
name: "深圳旗舰店",
loc: {type: "Point", coordinates: [114.06, 22.54]}
})
# 创建球面地理索引
db.store_info.createIndex({loc: "2dsphere"})
# 查询指定范围内的门店
db.store_info.find({
loc: {
$geoWithin: {$center: [[114.06,22.54], 0.1]}
}
})
5.4.5 索引管理命令
# 查看集合所有索引
db.user_info.getIndexes()
# 查看索引占用空间
db.user_info.totalIndexSize()
# 删除指定索引
db.user_info.dropIndex("age_1")
# 删除所有自定义索引(保留_id索引)
db.user_info.dropIndexes()
六、SpringBoot整合MongoDB企业级实战开发
SpringBoot整合MongoDB提供两种主流开发方式:MongoTemplate模板操作(灵活适配复杂SQL)、MongoRepository接口操作(简化CRUD),本章整合两种方式,封装企业级通用代码,适配生产开发。
6.1 项目依赖引入
SpringBoot2.7.x适配稳定依赖,无需额外冗余包,自动装配MongoDB核心配置。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/>
</parent>
<groupId>com.company.mongodb</groupId>
<artifactId>mongodb-demo</artifactId>
<version>1.0.0</version>
<name>MongoDB企业级实战项目</name>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- SpringBoot Web核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MongoDB自动装配依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- 工具类 -->
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
6.2 全局配置文件
配置MongoDB连接地址、数据库名称、连接池参数,优化高并发连接性能。
server:
port: 8090
servlet:
context-path: /
# MongoDB集群配置
spring:
data:
mongodb:
# 连接地址与数据库
host: 127.0.0.1
port: 27017
database: business_db
# 连接池配置
pool:
max-size: 100
min-size: 10
max-wait: 3000
max-idle-time: 60000
# 日志配置
logging:
level:
com.company.mongodb: debug
6.3 实体类封装(文档映射)
创建用户实体类,映射MongoDB文档结构,适配嵌套文档、数组字段。
package com.company.mongodb.entity;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoId;
import java.util.Date;
import java.util.List;
/**
* 用户文档实体类
* 映射mongodb user_info集合
*/
@Data
@Document(collection = "user_info")
public class UserInfo {
/**
* 文档唯一主键
*/
@MongoId
private String id;
/**
* 用户名
*/
@Field("username")
private String username;
/**
* 年龄
*/
@Field("age")
private Integer age;
/**
* 性别
*/
@Field("gender")
private String gender;
/**
* 是否VIP
*/
@Field("isVip")
private Boolean isVip;
/**
* 积分
*/
@Field("score")
private Double score;
/**
* 爱好数组
*/
@Field("hobbies")
private List<String> hobbies;
/**
* 创建时间
*/
@Field("createTime")
private Date createTime;
/**
* 更新时间
*/
@Field("updateTime")
private Date updateTime;
}
6.4 Repository接口极简CRUD
继承MongoRepository接口,无需编写SQL,自动实现增删改查、条件查询、分页排序。
package com.company.mongodb.repository;
import com.company.mongodb.entity.UserInfo;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 用户数据访问接口
* 继承MongoRepository实现极简CRUD
*/
@Repository
public interface UserInfoRepository extends MongoRepository<UserInfo, String> {
/**
* 根据用户名精准查询
*/
UserInfo findByUsername(String username);
/**
* 根据VIP状态和年龄范围查询用户
*/
List<UserInfo> findByIsVipAndAgeGreaterThan(Boolean isVip, Integer age);
/**
* 根据用户名删除用户
*/
void deleteByUsername(String username);
}
6.5 MongoTemplate复杂操作工具类
封装聚合查询、复杂条件筛选、分页、批量更新、地理查询等高阶功能,适配复杂业务场景。
package com.company.mongodb.util;
import com.company.mongodb.entity.UserInfo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
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.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* MongoDB高阶操作工具类
* 适配复杂查询、聚合统计、批量操作
*/
@Component
public class MongoDbUtil {
@Resource
private MongoTemplate mongoTemplate;
/**
* 分页条件查询用户
*/
public Page<UserInfo> pageQueryUser(Integer pageNum, Integer pageSize, Boolean isVip, Integer minAge) {
// 构建查询条件
Criteria criteria = new Criteria();
if (isVip != null) {
criteria.and("isVip").is(isVip);
}
if (minAge != null) {
criteria.and("age").gte(minAge);
}
Query query = new Query(criteria);
// 分页参数
PageRequest pageRequest = PageRequest.of(pageNum - 1, pageSize);
query.with(pageRequest);
// 查询数据与总条数
List<UserInfo> userList = mongoTemplate.find(query, UserInfo.class);
long total = mongoTemplate.count(query, UserInfo.class);
return new PageImpl<>(userList, pageRequest, total);
}
/**
* 批量更新用户积分
*/
public void batchUpdateUserScore(Integer addScore, Boolean isVip) {
Query query = new Query(Criteria.where("isVip").is(isVip));
Update update = new Update().inc("score", addScore);
mongoTemplate.updateMulti(query, update, UserInfo.class);
}
/**
* 聚合统计VIP/非VIP用户数量与平均积分
*/
public List<Map> aggregateUserStats() {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group("isVip")
.count().as("userCount")
.avg("score").as("avgScore")
);
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, "user_info", Map.class);
return results.getMappedResults();
}
}
6.6 统一返回结果与控制层接口
6.6.1 全局统一返回实体
package com.company.mongodb.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 全局统一接口返回结果
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private Integer code;
private String msg;
private T data;
public static <T> Result<T> success(T data) {
return new Result<>(200, "操作成功", data);
}
public static <T> Result<T> success() {
return new Result<>(200, "操作成功", null);
}
public static <T> Result<T> fail(String msg) {
return new Result<>(500, msg, null);
}
}
6.6.2 业务控制层接口
package com.company.mongodb.controller;
import com.company.mongodb.entity.Result;
import com.company.mongodb.entity.UserInfo;
import com.company.mongodb.repository.UserInfoRepository;
import com.company.mongodb.util.MongoDbUtil;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* MongoDB业务接口控制层
* 整合Repository简易操作 + MongoTemplate高阶操作
*/
@RestController
@RequestMapping("/mongodb/user")
public class UserController {
@Resource
private UserInfoRepository userInfoRepository;
@Resource
private MongoDbUtil mongoDbUtil;
/**
* 新增用户(Repository原生CRUD)
*/
@GetMapping("/save")
public Result<UserInfo> saveUser(UserInfo userInfo) {
UserInfo save = userInfoRepository.save(userInfo);
return Result.success(save);
}
/**
* 根据用户名查询用户
*/
@GetMapping("/getByUsername")
public Result<UserInfo> getByUsername(@RequestParam String username) {
UserInfo userInfo = userInfoRepository.findByUsername(username);
return Result.success(userInfo);
}
/**
* 分页条件查询用户(MongoTemplate高阶分页)
*/
@GetMapping("/page")
public Result<Page<UserInfo>> pageQueryUser(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "5") Integer pageSize,
@RequestParam(required = false) Boolean isVip,
@RequestParam(required = false) Integer minAge) {
Page<UserInfo> pageResult = mongoDbUtil.pageQueryUser(pageNum, pageSize, isVip, minAge);
return Result.success(pageResult);
}
/**
* 批量更新用户积分
*/
@GetMapping("/batchUpdateScore")
public Result<String> batchUpdateScore(
@RequestParam Integer addScore,
@RequestParam Boolean isVip) {
mongoDbUtil.batchUpdateUserScore(addScore, isVip);
return Result.success("批量更新用户积分成功");
}
/**
* 聚合统计VIP用户数据
*/
@GetMapping("/stats")
public Result<List<Map>> userStats() {
List<Map> stats = mongoDbUtil.aggregateUserStats();
return Result.success(stats);
}
/**
* 删除用户
*/
@GetMapping("/delete")
public Result<String> deleteUser(@RequestParam String username) {
userInfoRepository.deleteByUsername(username);
return Result.success("用户删除成功");
}
}
6.7 项目启动与接口测试
6.7.1 启动类编写
创建项目启动入口类,开启SpringBoot自动装配,无需额外配置即可整合MongoDB:
package com.company.mongodb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* MongoDB实战项目启动类
*/
@SpringBootApplication
public class MongodbApplication {
public static void main(String[] args) {
SpringApplication.run(MongodbApplication.class, args);
}
}
6.7.2 接口测试方式
项目启动成功后(默认端口8090),可通过Postman、浏览器、Apifox测试所有接口,核心测试接口如下:
-
新增用户:
http://localhost:8090/mongodb/user/save(GET传参) -
用户名查询:
http://localhost:8090/mongodb/user/getByUsername?username=wangwu -
分页查询:
http://localhost:8090/mongodb/user/page?pageNum=1&pageSize=5&isVip=true&minAge=25 -
批量积分更新:
http://localhost:8090/mongodb/user/batchUpdateScore?addScore=10&isVip=true -
用户数据聚合统计:
http://localhost:8090/mongodb/user/stats -
删除用户:
http://localhost:8090/mongodb/user/delete?username=tianqi
七、MongoDB生产调优与避坑指南
7.1 高频性能优化方案
7.1.1 索引优化核心准则
-
禁止无索引全表扫描,高频查询字段必须建立索引,查询条件字段优先建立单键/复合索引;
-
复合索引遵循等值在前、范围在后原则,例如:精准匹配字段+排序/范围字段;
-
避免创建冗余索引,重复字段索引会增加写入开销,定期清理无效索引;
-
数组字段查询必须使用多键索引,大幅提升数组匹配、筛选性能。
7.1.2 查询语句优化
-
查询时按需返回字段,通过
字段:1/_id:0屏蔽无效字段,减少数据传输开销; -
聚合管道优先前置
$match过滤数据,减少后续流水线数据处理量; -
大数据量查询必须分页,避免单次查询超16MB默认结果集上限;
-
禁止使用模糊全匹配查询(/xxx/),无法走索引,海量数据下性能极差。
7.1.3 服务配置调优
-
合理配置WiredTiger缓存,生产环境内存16G以上服务器,默认缓存配置可满足绝大多数场景;
-
开启日志轮转,避免日志文件过大占用磁盘,定期清理历史冗余日志;
-
连接池参数适配业务并发量,高并发场景调大最大连接数,避免连接超时阻塞。
7.2 企业开发常见坑点与解决方案
-
坑点1:字段类型不匹配导致查询失效
问题:数据库字段为数值型,代码传入字符串参数,索引失效查询无结果;
解决方案:统一代码与数据库字段类型,数值、字符串、日期类型严格对应。 -
坑点2:无事务导致数据一致性问题
问题:多文档操作中途报错,出现数据脏数据、数据不一致;
解决方案:MongoDB4.0+支持副本集事务、4.2+支持分片事务,多文档更新开启事务机制。 -
坑点3:嵌套层级过深导致查询卡顿
问题:文档嵌套层级超过5层,解析、查询性能大幅下降;
解决方案:复杂关联场景改用引用模型,控制嵌套层级在3层以内。 -
坑点4:批量操作无过滤条件引发全表更新/删除
问题:误执行无参数updateMany、deleteMany,导致全表数据篡改或丢失;
解决方案:生产环境禁止空条件批量操作,代码层增加参数校验拦截。 -
坑点5:索引过多影响写入性能
问题:集合索引数量过多,新增、修改数据需同步更新所有索引,导致写入卡顿;
解决方案:仅为查询、排序、筛选字段建索引,单集合索引数量不超过8个。
八、全文总结
本教程从理论、原理、部署、命令实操、代码整合、生产调优六个维度,完整覆盖MongoDB企业级落地全流程。核心内容总结如下:
1、MongoDB作为文档型NoSQL数据库,核心优势为无模式灵活存储、高并发读写、弹性扩容、适配非结构化数据,完美适配互联网快速迭代、海量数据、高并发业务场景。
2、核心数据模型依托BSON格式,通过内嵌文档、引用关联两种模型适配不同业务关联场景,规避关系型数据库多表JOIN性能短板。
3、生产环境优先使用WiredTiger存储引擎,依托文档级锁、MVCC机制、数据压缩能力,保障高并发、高可用、高存储效率。
4、支持YUM物理机、Docker容器两种生产部署方式,适配不同服务器环境,部署简单、运维成本低。
5、核心CRUD、聚合管道、多类型索引是业务开发核心,熟练掌握高阶语法可实现绝大部分数据分析、数据查询场景。
6、SpringBoot双方式整合(Repository+MongoTemplate),兼顾开发效率与业务灵活性,可直接复用至企业项目开发。
7、生产开发需严格遵循索引优化、查询优化规范,规避常见坑点,保障数据库高性能、高稳定运行。
更多推荐

所有评论(0)