MongoDB NoSQL 数据库实践文档
1. 引言
随着互联网的快速发展,传统的关系型数据库在处理大规模、高并发、非结构化数据时遇到了挑战。NoSQL数据库应运而生,它们提供了更灵活的数据模型、更好的扩展性和更高的性能,适用于现代Web应用、大数据分析、物联网等场景。
MongoDB是最流行的NoSQL数据库之一,它具有以下主要特点:
- 文档导向:使用JSON-like BSON格式存储数据,支持灵活的数据模型
- 高可用性:支持复制集,提供自动故障转移
- 可扩展性:支持分片,实现水平扩展
- 强大的查询语言:支持丰富的查询操作、索引和聚合
- 事务支持:支持多文档事务
- 灵活的数据模型:无需预先定义模式,支持动态字段和嵌套文档
本文将详细介绍MongoDB的核心概念、架构设计、安装配置、数据模型、查询语言、索引、聚合、事务、性能优化、安全等内容,并提供实际的Java代码示例,帮助读者快速上手MongoDB开发。
2. 核心概念
2.1 文档(Document)
文档是MongoDB的基本数据单元,类似于关系型数据库中的行。它是一个键值对的集合,使用JSON-like BSON格式存储。
示例文档:
json
{
"_id": ObjectId("60c5d8e8b3c7a1b2c3d4e5f6"),
"name": "张三",
"age": 30,
"email": "zhangsan@example.com",
"address": {
"city": "北京",
"street": "朝阳区建国路88号"
},
"hobbies": ["读书", "旅行", "摄影"]
}
2.2 集合(Collection)
集合是文档的集合,类似于关系型数据库中的表。它可以存储不同结构的文档,但通常存储具有相似结构的文档。
2.3 数据库(Database)
数据库是集合的容器,类似于关系型数据库中的数据库。MongoDB支持多个数据库,每个数据库都有自己的集合和用户权限。
2.4 字段(Field)
字段是文档中的键值对,类似于关系型数据库中的列。
2.5 索引(Index)
索引用于加速查询,类似于关系型数据库中的索引。MongoDB支持多种索引类型,如单字段索引、复合索引、地理空间索引等。
2.6 聚合(Aggregation)
聚合用于对文档进行数据处理和分析,类似于关系型数据库中的GROUP BY和HAVING子句。
2.7 复制集(Replica Set)
复制集是一组MongoDB实例,用于提供高可用性和数据冗余。它包含一个主节点和多个从节点,主节点负责处理写入操作,从节点负责复制主节点的数据。
2.8 分片(Sharding)
分片用于实现水平扩展,将数据分布在多个服务器上。它包含分片键、分片服务器、配置服务器和路由服务器。
2.9 事务(Transaction)
事务用于确保多个操作的原子性,支持多文档事务。
3. 架构设计
3.1 整体架构
MongoDB的整体架构包括以下组件:
- 客户端:应用程序通过MongoDB驱动连接到MongoDB服务器
- MongoDB服务器:处理客户端请求,存储和检索数据
- 存储引擎:负责数据的存储和检索,如WiredTiger、MMAPv1等
3.2 数据模型
MongoDB使用文档导向的数据模型,支持以下特性:
- 灵活的模式:无需预先定义模式,支持动态字段
- 嵌套文档:支持文档嵌套,减少表连接
- 数组:支持数组字段,便于存储列表数据
- 索引:支持多种索引类型,加速查询
3.3 复制集架构
复制集架构包括以下组件:
- 主节点(Primary):处理所有写入操作和部分读取操作
- 从节点(Secondary):复制主节点的数据,处理读取操作
- 仲裁节点(Arbiter):不存储数据,只参与选举
复制集的工作原理:
- 客户端将写入请求发送到主节点
- 主节点将写入操作记录到oplog中
- 从节点从主节点复制oplog并应用到自己的数据集
- 当主节点故障时,从节点通过选举产生新的主节点
3.4 分片架构
分片架构包括以下组件:
- 路由服务器(Mongos):接收客户端请求,将请求路由到相应的分片服务器
- 配置服务器(Config Server):存储分片集群的元数据
- 分片服务器(Shard):存储数据的分片,每个分片都是一个复制集
分片的工作原理:
- 客户端将请求发送到路由服务器
- 路由服务器根据分片键和配置信息,将请求路由到相应的分片服务器
- 分片服务器处理请求并返回结果
- 路由服务器将结果合并并返回给客户端
4. 安装与配置
4.1 环境准备
在安装MongoDB之前,需要准备以下环境:
- 操作系统:Windows、Linux或macOS
- 硬件:至少2GB RAM,10GB磁盘空间
- 网络:确保端口27017(默认端口)可用
4.2 安装MongoDB
4.2.1 Windows安装
- 下载MongoDB安装包:https://www.mongodb.com/try/download/community
- 运行安装程序,选择"Complete"安装类型
- 勾选"Install MongoDB Compass"(可选,图形化管理工具)
- 完成安装
4.2.2 Linux安装(Ubuntu)
- 导入MongoDB GPG密钥:
bash
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
- 添加MongoDB仓库:
bash
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list
- 更新包列表:
bash
sudo apt-get update
- 安装MongoDB:
bash
sudo apt-get install -y mongodb-org
- 启动MongoDB服务:
bash
sudo systemctl start mongod
sudo systemctl enable mongod
4.2.3 macOS安装(Homebrew)
bash
brew tap mongodb/brew
brew install mongodb-community
brew services start mongodb-community
4.3 配置MongoDB
MongoDB的配置文件位于:
- Windows:
C:\Program Files\MongoDB\Server\5.0\bin\mongod.cfg - Linux:
/etc/mongod.conf - macOS:
/usr/local/etc/mongod.conf
主要配置项:
yaml
# 存储配置
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
# 日志配置
operationProfiling:
slowOpThresholdMs: 100
mode: slowOp
# 网络配置
net:
port: 27017
bindIp: 127.0.0.1
# 复制集配置
replication:
replSetName: "rs0"
# 分片配置
sharding:
clusterRole: "configsvr"
4.4 启动MongoDB
4.4.1 Windows
bash
# 启动MongoDB服务
net start MongoDB
# 停止MongoDB服务
net stop MongoDB
4.4.2 Linux
bash
# 启动MongoDB服务
sudo systemctl start mongod
# 停止MongoDB服务
sudo systemctl stop mongod
# 重启MongoDB服务
sudo systemctl restart mongod
# 查看MongoDB服务状态
sudo systemctl status mongod
4.5 连接MongoDB
使用mongo shell连接MongoDB:
bash
mongo
连接到指定主机和端口:
bash
mongo --host 127.0.0.1 --port 27017
连接到指定数据库:
bash
mongo mydatabase
使用认证连接:
bash
mongo -u admin -p password --authenticationDatabase admin
5. 基本操作
5.1 数据库操作
javascript
// 查看所有数据库
show dbs
// 使用或创建数据库
use mydatabase
// 查看当前数据库
db
// 查看数据库大小
db.stats()
// 删除当前数据库
db.dropDatabase()
5.2 集合操作
javascript
// 创建集合
db.createCollection("users")
// 查看所有集合
show collections
// 查看集合状态
db.users.stats()
// 删除集合
db.users.drop()
5.3 文档操作(CURD)
5.3.1 创建文档(Create)
javascript
// 插入单个文档
db.users.insertOne({
name: "张三",
age: 30,
email: "zhangsan@example.com"
})
// 插入多个文档
db.users.insertMany([
{
name: "李四",
age: 25,
email: "lisi@example.com"
},
{
name: "王五",
age: 35,
email: "wangwu@example.com"
}
])
5.3.2 读取文档(Read)
javascript
// 查询所有文档
db.users.find()
// 查询单个文档
db.users.findOne({ name: "张三" })
// 条件查询
db.users.find({ age: { $gt: 25 } })
// 投影查询(只返回指定字段)
db.users.find({ age: { $gt: 25 } }, { name: 1, email: 1 })
// 排序查询
db.users.find().sort({ age: -1 })
// 分页查询
db.users.find().skip(10).limit(10)
5.3.3 更新文档(Update)
javascript
// 更新单个文档
db.users.updateOne(
{ name: "张三" },
{ $set: { age: 31 } }
)
// 更新多个文档
db.users.updateMany(
{ age: { $lt: 30 } },
{ $set: { status: "young" } }
)
// 替换文档
db.users.replaceOne(
{ name: "张三" },
{
name: "张三",
age: 32,
email: "zhangsan@newexample.com"
}
)
5.3.4 删除文档(Delete)
javascript
// 删除单个文档
db.users.deleteOne({ name: "张三" })
// 删除多个文档
db.users.deleteMany({ age: { $gt: 35 } })
5.4 查询操作符
5.4.1 比较操作符
| 操作符 | 描述 | 示例 |
|---|---|---|
| $eq | 等于 | { age: { $eq: 30 } } |
| $ne | 不等于 | { age: { $ne: 30 } } |
| $gt | 大于 | { age: { $gt: 30 } } |
| $gte | 大于等于 | { age: { $gte: 30 } } |
| $lt | 小于 | { age: { $lt: 30 } } |
| $lte | 小于等于 | { age: { $lte: 30 } } |
| $in | 在指定数组中 | { age: { $in: [25, 30, 35] } } |
| $nin | 不在指定数组中 | { age: { $nin: [25, 30, 35] } } |
5.4.2 逻辑操作符
| 操作符 | 描述 | 示例 |
|---|---|---|
| $and | 逻辑与 | { $and: [{ age: { $gt: 25 } }, { age: { $lt: 35 } }] } |
| $or | 逻辑或 | { $or: [{ age: { $lt: 25 } }, { age: { $gt: 35 } }] } |
| $not | 逻辑非 | { age: { $not: { $eq: 30 } } } |
| $nor | 逻辑与非 | { $nor: [{ age: { $lt: 25 } }, { age: { $gt: 35 } }] } |
5.4.3 数组操作符
| 操作符 | 描述 | 示例 |
|---|---|---|
| $all | 包含所有指定元素 | { hobbies: { $all: ["读书", "旅行"] } } |
| $elemMatch | 数组元素匹配条件 | { scores: { $elemMatch: { $gt: 80, $lt: 90 } } } |
| $size | 数组大小 | { hobbies: { $size: 3 } } |
5.4.4 其他操作符
| 操作符 | 描述 | 示例 |
|---|---|---|
| $exists | 字段存在 | { email: { $exists: true } } |
| $type | 字段类型 | { age: { $type: "number" } } |
| $regex | 正则表达式 | { email: { $regex: /example\.com$/ } } |
6. 数据模型设计
6.1 文档设计原则
- 应用驱动设计:根据应用需求设计数据模型
- 避免过度规范化:使用嵌入减少表连接
- 考虑查询模式:根据查询模式设计索引和数据结构
- 使用适当的数据类型:选择合适的数据类型存储数据
- 避免文档过大:单个文档大小不超过16MB
6.2 数据关系建模
MongoDB支持两种数据关系建模方式:
- 嵌入(Embedding):将相关数据嵌入到同一文档中
- 引用(Referencing):使用引用指向其他文档
6.2.1 嵌入(Embedding)
嵌入适用于:
- 一对一关系
- 一对多关系(子文档数量少)
- 经常一起查询的数据
示例:
json
{
"_id": ObjectId("60c5d8e8b3c7a1b2c3d4e5f6"),
"name": "张三",
"age": 30,
"email": "zhangsan@example.com",
"address": {
"city": "北京",
"street": "朝阳区建国路88号"
}
}
6.2.2 引用(Referencing)
引用适用于:
- 一对多关系(子文档数量多)
- 多对多关系
- 数据经常更新
示例:
json
// 用户文档
{
"_id": ObjectId("60c5d8e8b3c7a1b2c3d4e5f6"),
"name": "张三",
"age": 30,
"email": "zhangsan@example.com"
}
// 订单文档
{
"_id": ObjectId("60c5d8e8b3c7a1b2c3d4e5f7"),
"userId": ObjectId("60c5d8e8b3c7a1b2c3d4e5f6"),
"orderDate": ISODate("2023-06-01T10:00:00Z"),
"total": 1000
}
6.3 模式验证
MongoDB支持模式验证,可以确保文档符合指定的模式。
javascript
// 创建集合时指定模式验证
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "age", "email"],
properties: {
name: {
bsonType: "string",
description: "Name must be a string and is required"
},
age: {
bsonType: "int",
minimum: 18,
maximum: 120,
description: "Age must be an integer between 18 and 120"
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
description: "Email must be a valid email address"
}
}
}
}
})
7. 索引优化
7.1 索引类型
7.1.1 单字段索引
javascript
db.users.createIndex({ name: 1 })
7.1.2 复合索引
javascript
db.users.createIndex({ name: 1, age: -1 })
7.1.3 唯一索引
javascript
db.users.createIndex({ email: 1 }, { unique: true })
7.1.4 多键索引
javascript
db.users.createIndex({ hobbies: 1 })
7.1.5 地理空间索引
javascript
db.places.createIndex({ location: "2dsphere" })
7.1.6 文本索引
javascript
db.articles.createIndex({ title: "text", content: "text" })
7.2 索引管理
javascript
// 创建索引
db.users.createIndex({ name: 1 })
// 查看索引
db.users.getIndexes()
// 删除索引
db.users.dropIndex({ name: 1 })
// 删除所有索引
db.users.dropIndexes()
7.3 索引性能分析
javascript
// 查看查询执行计划
db.users.find({ name: "张三", age: { $gt: 30 } }).explain()
// 分析查询性能
db.users.find({ name: "张三", age: { $gt: 30 } }).explain("executionStats")
7.4 索引最佳实践
- 为经常查询的字段创建索引
- 使用复合索引覆盖多个查询条件
- 避免创建过多索引
- 考虑索引的选择性
- 使用索引排序
- 避免在索引字段上进行复杂操作
8. 聚合框架
8.1 聚合管道
聚合管道是一系列数据处理阶段,每个阶段接收输入文档并产生输出文档。
javascript
db.users.aggregate([
// 匹配阶段
{ $match: { age: { $gt: 25 } } },
// 分组阶段
{ $group: { _id: "$city", count: { $sum: 1 }, avgAge: { $avg: "$age" } } },
// 排序阶段
{ $sort: { count: -1 } },
// 限制阶段
{ $limit: 10 }
])
8.2 常用聚合操作符
8.2.1 管道操作符
| 操作符 | 描述 | 示例 |
|---|---|---|
| $match | 过滤文档 | { $match: { age: { $gt: 25 } } } |
| $project | 投影文档 | { $project: { name: 1, age: 1 } } |
| $group | 分组文档 | { $group: { _id: "$city", count: { $sum: 1 } } } |
| $sort | 排序文档 | { $sort: { count: -1 } } |
| $limit | 限制文档数量 | { $limit: 10 } |
| $skip | 跳过文档 | { $skip: 10 } |
| $unwind | 展开数组 | { $unwind: "$hobbies" } |
| $lookup | 左外连接 | { $lookup: { from: "orders", localField: "_id", foreignField: "userId", as: "orders" } } |
8.2.2 表达式操作符
| 操作符 | 描述 | 示例 |
|---|---|---|
| $sum | 求和 | { $sum: "$amount" } |
| $avg | 平均值 | { $avg: "$age" } |
| $min | 最小值 | { $min: "$price" } |
| $max | 最大值 | { $max: "$score" } |
| $count | 计数 | { $count: "total" } |
| $first | 第一个值 | { $first: "$name" } |
| $last | 最后一个值 | { $last: "$name" } |
8.3 聚合案例
8.3.1 计算每个城市的用户数量和平均年龄
javascript
db.users.aggregate([
{ $group: { _id: "$address.city", count: { $sum: 1 }, avgAge: { $avg: "$age" } } },
{ $sort: { count: -1 } }
])
8.3.2 计算每个用户的订单总金额
javascript
db.users.aggregate([
{ $lookup: { from: "orders", localField: "_id", foreignField: "userId", as: "orders" } },
{ $unwind: "$orders" },
{ $group: { _id: "$name", totalAmount: { $sum: "$orders.total" } } },
{ $sort: { totalAmount: -1 } }
])
9. 事务
9.1 事务概述
MongoDB支持多文档事务,确保多个操作的原子性。事务适用于:
- 需要同时修改多个文档
- 需要确保数据一致性
- 需要回滚操作
9.2 事务操作
9.2.1 使用mongo shell
javascript
// 启动事务
var session = db.getMongo().startSession()
var transactionOptions = {
readConcern: { level: "snapshot" },
writeConcern: { w: "majority" },
readPreference: "primary"
}
// 执行事务
try {
session.startTransaction(transactionOptions)
var usersCollection = session.getDatabase("mydatabase").users
var ordersCollection = session.getDatabase("mydatabase").orders
// 插入用户
var userResult = usersCollection.insertOne({
name: "王五",
age: 35,
email: "wangwu@example.com"
})
// 插入订单
var orderResult = ordersCollection.insertOne({
userId: userResult.insertedId,
orderDate: new Date(),
total: 1500
})
// 提交事务
session.commitTransaction()
print("Transaction committed successfully")
} catch (error) {
// 回滚事务
session.abortTransaction()
print("Transaction aborted:", error)
} finally {
// 结束会话
session.endSession()
}
9.2.2 使用Java驱动
java
// 创建MongoClient
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
// 获取数据库和集合
MongoDatabase database = mongoClient.getDatabase("mydatabase");
MongoCollection<Document> usersCollection = database.getCollection("users");
MongoCollection<Document> ordersCollection = database.getCollection("orders");
// 启动事务
try (ClientSession session = mongoClient.startSession()) {
// 事务选项
TransactionOptions transactionOptions = TransactionOptions.builder()
.readPreference(ReadPreference.primary())
.readConcern(ReadConcern.SNAPSHOT)
.writeConcern(WriteConcern.MAJORITY)
.build();
// 执行事务
session.withTransaction(() -> {
// 插入用户
Document user = new Document("name", "王五")
.append("age", 35)
.append("email", "wangwu@example.com");
InsertOneResult userResult = usersCollection.insertOne(session, user);
// 插入订单
Document order = new Document("userId", userResult.getInsertedId())
.append("orderDate", new Date())
.append("total", 1500);
ordersCollection.insertOne(session, order);
return true;
}, transactionOptions);
System.out.println("Transaction committed successfully");
} catch (MongoException e) {
System.err.println("Transaction aborted:");
e.printStackTrace();
}
9.3 事务最佳实践
- 尽量减少事务的持续时间
- 避免在事务中执行长时间运行的操作
- 使用适当的读写关注
- 考虑事务的重试机制
- 避免在事务中使用过多的集合
10. 复制集
10.1 复制集概述
复制集是一组MongoDB实例,用于提供高可用性和数据冗余。它包含:
- 主节点(Primary):处理所有写入操作和部分读取操作
- 从节点(Secondary):复制主节点的数据,处理读取操作
- 仲裁节点(Arbiter):不存储数据,只参与选举
10.2 复制集配置
bash
# 启动三个MongoDB实例
mongod --port 27017 --dbpath /data/db1 --replSet rs0
mongod --port 27018 --dbpath /data/db2 --replSet rs0
mongod --port 27019 --dbpath /data/db3 --replSet rs0
# 连接到主节点
mongo --port 27017
# 初始化复制集
rs.initiate()
# 添加从节点
rs.add("localhost:27018")
rs.add("localhost:27019")
# 添加仲裁节点
rs.addArb("localhost:27020")
# 查看复制集状态
rs.status()
# 查看复制集配置
rs.conf()
10.3 复制集故障转移
当主节点故障时,从节点通过选举产生新的主节点。选举过程如下:
- 从节点检测到主节点故障
- 从节点发起选举
- 其他从节点投票
- 获得多数票的从节点成为新的主节点
10.4 复制集管理
javascript
// 查看复制集状态
rs.status()
// 查看复制集配置
rs.conf()
// 重新配置复制集
cfg = rs.conf()
cfg.members[0].priority = 2
rs.reconfig(cfg)
// 降级主节点
rs.stepDown()
// 强制重新选举
rs.freeze(0)
rs.electionTimeoutMillis(5000)
11. 分片
11.1 分片概述
分片用于实现水平扩展,将数据分布在多个服务器上。它包含:
- 路由服务器(Mongos):接收客户端请求,将请求路由到相应的分片服务器
- 配置服务器(Config Server):存储分片集群的元数据
- 分片服务器(Shard):存储数据的分片,每个分片都是一个复制集
11.2 分片配置
bash
# 启动配置服务器
mongod --configsvr --replSet csReplSet --port 27019 --dbpath /data/configdb
# 初始化配置服务器复制集
mongo --port 27019
rs.initiate()
# 启动路由服务器
mongos --configdb csReplSet/localhost:27019 --port 27017
# 启动分片服务器
mongod --shardsvr --replSet rs0 --port 27020 --dbpath /data/shard1
mongod --shardsvr --replSet rs1 --port 27021 --dbpath /data/shard2
# 初始化分片服务器复制集
mongo --port 27020
rs.initiate()
mongo --port 27021
rs.initiate()
# 添加分片到集群
mongo --port 27017
sh.addShard("rs0/localhost:27020")
sh.addShard("rs1/localhost:27021")
# 启用数据库分片
sh.enableSharding("mydatabase")
# 为集合创建分片键
sh.shardCollection("mydatabase.users", { "_id": "hashed" })
sh.shardCollection("mydatabase.orders", { "userId": 1, "orderDate": 1 })
11.3 分片键选择
分片键是用于分布数据的字段,选择合适的分片键非常重要。分片键应该:
- 具有高选择性
- 均匀分布
- 支持查询模式
11.4 分片管理
javascript
// 查看分片状态
sh.status()
// 查看分片集合
sh.getShardedCollections()
// 查看分片键
sh.getShardDistribution("mydatabase.users")
// 添加分片
sh.addShard("rs2/localhost:27022")
// 移除分片
sh.removeShard("rs2")
12. 性能优化
12.1 查询优化
- 使用索引
- 避免全表扫描
- 使用投影查询
- 使用聚合管道
- 避免在查询中使用正则表达式
- 避免在查询中使用$where
12.2 索引优化
- 创建合适的索引
- 使用复合索引
- 考虑索引的选择性
- 避免创建过多索引
- 定期重建索引
12.3 内存优化
- 合理设置WiredTiger缓存大小
- 使用索引覆盖查询
- 避免大文档
- 使用TTL索引自动删除过期数据
12.4 存储优化
- 使用压缩
- 合理设置块大小
- 使用WiredTiger存储引擎
- 定期压缩集合
12.5 并发控制
- 使用适当的读写关注
- 避免长时间运行的事务
- 使用连接池
- 合理设置最大连接数
13. 安全
13.1 认证与授权
13.1.1 启用认证
- 创建管理员用户:
javascript
use admin
db.createUser({
user: "admin",
pwd: "password",
roles: [{ role: "userAdminAnyDatabase", db: "admin" }, { role: "root", db: "admin" }]
})
- 修改配置文件启用认证:
yaml
security:
authorization: enabled
- 重启MongoDB服务:
bash
sudo systemctl restart mongod
13.1.2 用户管理
javascript
// 创建用户
use mydatabase
db.createUser({
user: "user",
pwd: "password",
roles: [{ role: "readWrite", db: "mydatabase" }]
})
// 修改用户密码
db.changeUserPassword("user", "newpassword")
// 删除用户
db.dropUser("user")
// 查看用户
db.getUser("user")
db.getUsers()
13.2 角色与权限
MongoDB提供了丰富的内置角色:
- 数据库角色:read、readWrite、dbAdmin、dbOwner、userAdmin
- 集群角色:clusterAdmin、clusterManager、clusterMonitor、hostManager
- 备份角色:backup、restore
- 超级角色:root、userAdminAnyDatabase
13.3 加密
13.3.1 传输加密(TLS/SSL)
- 生成证书:
bash
openssl req -newkey rsa:2048 -new -x509 -days 365 -nodes -out mongodb-cert.crt -keyout mongodb-cert.key
cat mongodb-cert.key mongodb-cert.crt > mongodb.pem
- 修改配置文件启用TLS/SSL:
yaml
net:
ssl:
mode: requireSSL
PEMKeyFile: /etc/ssl/mongodb.pem
CAFile: /etc/ssl/ca.pem
- 重启MongoDB服务:
bash
sudo systemctl restart mongod
13.3.2 静态加密
MongoDB Enterprise支持静态加密,可以加密存储在磁盘上的数据。
13.4 网络安全
- 限制绑定IP:
yaml
net:
bindIp: 127.0.0.1
- 使用防火墙:
bash
# 允许27017端口
sudo ufw allow 27017/tcp
13.5 审计
MongoDB Enterprise支持审计功能,可以记录数据库的操作。
yaml
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/audit.log
filter: '{ "atype": { "$in": [ "authCheck", "createCollection", "dropCollection" ] } }'
14. 监控与维护
14.1 监控工具
- MongoDB Compass:图形化管理工具
- MongoDB Cloud Manager:云监控工具
- Prometheus + Grafana:开源监控工具
14.2 监控指标
- 连接数:db.serverStatus().connections
- 操作数:db.serverStatus().opcounters
- 索引使用情况:db.serverStatus().indexCounters
- 内存使用情况:db.serverStatus().mem
- 存储使用情况:db.serverStatus().storageEngine
14.3 备份与恢复
14.3.1 备份
bash
# 全量备份
mongodump --db mydatabase --out /backup/$(date +%Y%m%d)
# 增量备份
mongodump --oplog --out /backup/$(date +%Y%m%d)
# 压缩备份
mongodump --db mydatabase --gzip --out /backup/$(date +%Y%m%d)
14.3.2 恢复
bash
# 全量恢复
mongorestore --db mydatabase /backup/20230601/mydatabase
# 增量恢复
mongorestore --oplogReplay /backup/20230601
# 压缩恢复
mongorestore --gzip --db mydatabase /backup/20230601/mydatabase
14.4 日志管理
MongoDB的日志文件包含详细的操作信息,可以用于调试和问题定位。
yaml
# 日志配置
operationProfiling:
slowOpThresholdMs: 100
mode: slowOp
# 日志级别
logLevel: 0
15. MongoDB与Java集成
15.1 MongoDB Java驱动
15.1.1 添加依赖
xml
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.6.0</version>
</dependency>
15.1.2 基本操作
java
import com.mongodb.client.*;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import org.bson.types.ObjectId;
import java.util.Date;
import java.util.List;
public class MongoDBJavaExample {
public static void main(String[] args) {
// 创建MongoClient
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
// 获取数据库
MongoDatabase database = mongoClient.getDatabase("mydatabase");
// 获取集合
MongoCollection<Document> collection = database.getCollection("users");
// 插入文档
Document user = new Document("name", "张三")
.append("age", 30)
.append("email", "zhangsan@example.com")
.append("registrationDate", new Date());
collection.insertOne(user);
// 查询文档
Document foundUser = collection.find(Filters.eq("name", "张三")).first();
System.out.println("Found user: " + foundUser.toJson());
// 更新文档
collection.updateOne(Filters.eq("name", "张三"), Updates.set("age", 31));
// 删除文档
collection.deleteOne(Filters.eq("name", "张三"));
// 关闭MongoClient
mongoClient.close();
}
}
15.2 Spring Data MongoDB
Spring Data MongoDB提供了更高级的抽象,便于在Spring应用中使用MongoDB。
15.2.1 添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.6.8</version>
</dependency>
15.2.2 配置文件
yaml
spring:
data:
mongodb:
uri: mongodb://localhost:27017/mydatabase
username: user
password: password
authentication-database: admin
15.2.3 实体类
java
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
import java.util.List;
@Document(collection = "users")
public class User {
@Id
private ObjectId id;
private String name;
private int age;
private String email;
private Address address;
private List<String> hobbies;
private Date registrationDate;
// 构造函数、getter和setter
}
public class Address {
private String city;
private String street;
private String zipCode;
// 构造函数、getter和setter
}
15.2.4 仓库接口
java
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import java.util.List;
public interface UserRepository extends MongoRepository<User, ObjectId> {
// 自定义查询方法
List<User> findByAgeGreaterThan(int age);
// 使用@Query注解
@Query("{ 'email': ?0 }")
User findByEmail(String email);
// 分页查询
Page<User> findByCity(String city, Pageable pageable);
}
15.2.5 服务类
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 创建用户
public User createUser(User user) {
return userRepository.save(user);
}
// 获取所有用户
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 根据ID获取用户
public Optional<User> getUserById(ObjectId id) {
return userRepository.findById(id);
}
// 更新用户
public User updateUser(ObjectId id, User user) {
user.setId(id);
return userRepository.save(user);
}
// 删除用户
public void deleteUser(ObjectId id) {
userRepository.deleteById(id);
}
// 根据年龄查询用户
public List<User> getUsersByAgeGreaterThan(int age) {
return userRepository.findByAgeGreaterThan(age);
}
}
16. 最佳实践
16.1 数据模型设计最佳实践
- 应用驱动设计:根据应用需求设计数据模型
- 避免过度规范化:使用嵌入减少表连接
- 考虑查询模式:根据查询模式设计索引和数据结构
- 使用适当的数据类型:选择合适的数据类型存储数据
- 避免文档过大:单个文档大小不超过16MB
16.2 查询优化最佳实践
- 使用索引:为经常查询的字段创建索引
- 避免全表扫描:使用合适的查询条件
- 使用投影查询:只返回需要的字段
- 使用聚合管道:处理复杂查询
- 避免在查询中使用正则表达式:正则表达式会影响性能
16.3 索引最佳实践
- 创建合适的索引:为经常查询的字段创建索引
- 使用复合索引:覆盖多个查询条件
- 避免创建过多索引:索引会影响写入性能
- 考虑索引的选择性:选择选择性高的字段
- 使用索引排序:使用索引进行排序
16.4 性能优化最佳实践
- 使用适当的读写关注:根据应用需求选择读写关注
- 避免长时间运行的事务:减少事务的持续时间
- 使用连接池:提高连接利用率
- 合理设置最大连接数:避免资源耗尽
- 使用压缩:减少存储和网络传输
16.5 安全最佳实践
- 启用认证和授权:保护数据库安全
- 使用强密码:避免使用弱密码
- 限制绑定IP:只允许必要的IP访问
- 使用TLS/SSL:加密网络通信
- 定期更新MongoDB:修复安全漏洞
17. 总结
MongoDB是一个功能强大的NoSQL数据库,具有以下主要特点:
- 文档导向:使用JSON-like BSON格式存储数据,支持灵活的数据模型
- 高可用性:支持复制集,提供自动故障转移
- 可扩展性:支持分片,实现水平扩展
- 强大的查询语言:支持丰富的查询操作、索引和聚合
- 事务支持:支持多文档事务
- 灵活的数据模型:无需预先定义模式,支持动态字段和嵌套文档
通过本文的学习,读者可以了解MongoDB的核心概念、架构设计、安装配置、数据模型、查询语言、索引、聚合、事务、性能优化、安全等内容,并能够使用MongoDB构建高性能、可靠的应用程序。
在实际项目中,MongoDB可以帮助开发者解决大规模、高并发、非结构化数据的存储和处理问题,适用于现代Web应用、大数据分析、物联网等场景。随着NoSQL数据库的广泛应用,MongoDB将成为构建现代应用程序的重要组件。