MongoDB NoSQL 数据库实践文档

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):不存储数据,只参与选举

复制集的工作原理:

  1. 客户端将写入请求发送到主节点
  2. 主节点将写入操作记录到oplog中
  3. 从节点从主节点复制oplog并应用到自己的数据集
  4. 当主节点故障时,从节点通过选举产生新的主节点

3.4 分片架构

分片架构包括以下组件:

  • 路由服务器(Mongos):接收客户端请求,将请求路由到相应的分片服务器
  • 配置服务器(Config Server):存储分片集群的元数据
  • 分片服务器(Shard):存储数据的分片,每个分片都是一个复制集

分片的工作原理:

  1. 客户端将请求发送到路由服务器
  2. 路由服务器根据分片键和配置信息,将请求路由到相应的分片服务器
  3. 分片服务器处理请求并返回结果
  4. 路由服务器将结果合并并返回给客户端

4. 安装与配置

4.1 环境准备

在安装MongoDB之前,需要准备以下环境:

  • 操作系统:Windows、Linux或macOS
  • 硬件:至少2GB RAM,10GB磁盘空间
  • 网络:确保端口27017(默认端口)可用

4.2 安装MongoDB

4.2.1 Windows安装
  1. 下载MongoDB安装包:https://www.mongodb.com/try/download/community
  2. 运行安装程序,选择"Complete"安装类型
  3. 勾选"Install MongoDB Compass"(可选,图形化管理工具)
  4. 完成安装
4.2.2 Linux安装(Ubuntu)
  1. 导入MongoDB GPG密钥:
bash 复制代码
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -
  1. 添加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
  1. 更新包列表:
bash 复制代码
sudo apt-get update
  1. 安装MongoDB:
bash 复制代码
sudo apt-get install -y mongodb-org
  1. 启动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 文档设计原则

  1. 应用驱动设计:根据应用需求设计数据模型
  2. 避免过度规范化:使用嵌入减少表连接
  3. 考虑查询模式:根据查询模式设计索引和数据结构
  4. 使用适当的数据类型:选择合适的数据类型存储数据
  5. 避免文档过大:单个文档大小不超过16MB

6.2 数据关系建模

MongoDB支持两种数据关系建模方式:

  1. 嵌入(Embedding):将相关数据嵌入到同一文档中
  2. 引用(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 索引最佳实践

  1. 为经常查询的字段创建索引
  2. 使用复合索引覆盖多个查询条件
  3. 避免创建过多索引
  4. 考虑索引的选择性
  5. 使用索引排序
  6. 避免在索引字段上进行复杂操作

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 事务最佳实践

  1. 尽量减少事务的持续时间
  2. 避免在事务中执行长时间运行的操作
  3. 使用适当的读写关注
  4. 考虑事务的重试机制
  5. 避免在事务中使用过多的集合

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 复制集故障转移

当主节点故障时,从节点通过选举产生新的主节点。选举过程如下:

  1. 从节点检测到主节点故障
  2. 从节点发起选举
  3. 其他从节点投票
  4. 获得多数票的从节点成为新的主节点

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 查询优化

  1. 使用索引
  2. 避免全表扫描
  3. 使用投影查询
  4. 使用聚合管道
  5. 避免在查询中使用正则表达式
  6. 避免在查询中使用$where

12.2 索引优化

  1. 创建合适的索引
  2. 使用复合索引
  3. 考虑索引的选择性
  4. 避免创建过多索引
  5. 定期重建索引

12.3 内存优化

  1. 合理设置WiredTiger缓存大小
  2. 使用索引覆盖查询
  3. 避免大文档
  4. 使用TTL索引自动删除过期数据

12.4 存储优化

  1. 使用压缩
  2. 合理设置块大小
  3. 使用WiredTiger存储引擎
  4. 定期压缩集合

12.5 并发控制

  1. 使用适当的读写关注
  2. 避免长时间运行的事务
  3. 使用连接池
  4. 合理设置最大连接数

13. 安全

13.1 认证与授权

13.1.1 启用认证
  1. 创建管理员用户:
javascript 复制代码
use admin
db.createUser({
  user: "admin",
  pwd: "password",
  roles: [{ role: "userAdminAnyDatabase", db: "admin" }, { role: "root", db: "admin" }]
})
  1. 修改配置文件启用认证:
yaml 复制代码
security:
  authorization: enabled
  1. 重启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)
  1. 生成证书:
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
  1. 修改配置文件启用TLS/SSL:
yaml 复制代码
net:
  ssl:
    mode: requireSSL
    PEMKeyFile: /etc/ssl/mongodb.pem
    CAFile: /etc/ssl/ca.pem
  1. 重启MongoDB服务:
bash 复制代码
sudo systemctl restart mongod
13.3.2 静态加密

MongoDB Enterprise支持静态加密,可以加密存储在磁盘上的数据。

13.4 网络安全

  1. 限制绑定IP
yaml 复制代码
net:
  bindIp: 127.0.0.1
  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 数据模型设计最佳实践

  1. 应用驱动设计:根据应用需求设计数据模型
  2. 避免过度规范化:使用嵌入减少表连接
  3. 考虑查询模式:根据查询模式设计索引和数据结构
  4. 使用适当的数据类型:选择合适的数据类型存储数据
  5. 避免文档过大:单个文档大小不超过16MB

16.2 查询优化最佳实践

  1. 使用索引:为经常查询的字段创建索引
  2. 避免全表扫描:使用合适的查询条件
  3. 使用投影查询:只返回需要的字段
  4. 使用聚合管道:处理复杂查询
  5. 避免在查询中使用正则表达式:正则表达式会影响性能

16.3 索引最佳实践

  1. 创建合适的索引:为经常查询的字段创建索引
  2. 使用复合索引:覆盖多个查询条件
  3. 避免创建过多索引:索引会影响写入性能
  4. 考虑索引的选择性:选择选择性高的字段
  5. 使用索引排序:使用索引进行排序

16.4 性能优化最佳实践

  1. 使用适当的读写关注:根据应用需求选择读写关注
  2. 避免长时间运行的事务:减少事务的持续时间
  3. 使用连接池:提高连接利用率
  4. 合理设置最大连接数:避免资源耗尽
  5. 使用压缩:减少存储和网络传输

16.5 安全最佳实践

  1. 启用认证和授权:保护数据库安全
  2. 使用强密码:避免使用弱密码
  3. 限制绑定IP:只允许必要的IP访问
  4. 使用TLS/SSL:加密网络通信
  5. 定期更新MongoDB:修复安全漏洞

17. 总结

MongoDB是一个功能强大的NoSQL数据库,具有以下主要特点:

  • 文档导向:使用JSON-like BSON格式存储数据,支持灵活的数据模型
  • 高可用性:支持复制集,提供自动故障转移
  • 可扩展性:支持分片,实现水平扩展
  • 强大的查询语言:支持丰富的查询操作、索引和聚合
  • 事务支持:支持多文档事务
  • 灵活的数据模型:无需预先定义模式,支持动态字段和嵌套文档

通过本文的学习,读者可以了解MongoDB的核心概念、架构设计、安装配置、数据模型、查询语言、索引、聚合、事务、性能优化、安全等内容,并能够使用MongoDB构建高性能、可靠的应用程序。

在实际项目中,MongoDB可以帮助开发者解决大规模、高并发、非结构化数据的存储和处理问题,适用于现代Web应用、大数据分析、物联网等场景。随着NoSQL数据库的广泛应用,MongoDB将成为构建现代应用程序的重要组件。

相关推荐
i***11862 小时前
【Sql Server】随机查询一条表记录,并重重温回顾下存储过程的封装和使用
数据库·oracle
2301_789380496 小时前
vsc中使用DBHub-MCP连接云Mysql到vsc-copilot
数据库·mysql
杨DaB6 小时前
【MySQL】02 数据库的基本操作
数据库·mysql·oracle
m***66736 小时前
SQL 实战—递归 SQL:层级结构查询与处理树形数据
java·数据库·sql
昙鱼7 小时前
Markdown文件导入Milvus向量数据库完整指南
数据库·ai·milvus
A__tao7 小时前
gotool.top 的 SQL 转 Markdown
数据库·sql
Austindatabases7 小时前
基于SQLite如何设计应用程序,拆散,散,还的散!
数据库·sqlite
马克学长9 小时前
SSM面向乡村振兴服务的产教融合服务平台521gh(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·乡村振兴·ssm 框架·服务平台
u***27619 小时前
C#数据库操作系列---SqlSugar完结篇
网络·数据库·c#