欢迎光临
我们一直在努力

MongoDB 6.0 从入门到整合:一份面向Java开发者的实战指南

一、MongoDB简介:为什么选择文档数据库?

1.1 什么是MongoDB?

MongoDB是一个使用C++编写的文档数据库,其核心数据模型为JSON/BSON。它巧妙地位于关系型与非关系型数据库之间,被誉为“功能最丰富、最像关系数据库的NoSQL数据库”。

核心特点:

  • 灵活的模式:集合中的文档无需拥有相同的字段,支持嵌套文档和数组

  • 强大的查询语言:语法类似面向对象查询,几乎实现关系型数据库单表查询所有功能

  • 完整的事务支持:支持ACID事务,满足企业级应用需求

  • 高性能与高扩展:原生支持复制集和分片集群

根据DB-Engines 2021年12月排名,MongoDB在全部数据库中位列第5,在NoSQL数据库中排名第一,其社区活跃度和应用广度持续上升。

1.2 MongoDB vs 关系型数据库:概念映射

MongoDB概念关系型数据库概念说明
数据库(database) 数据库(database) 逻辑命名空间
集合(collection) 表(table) 文档的容器
文档(document) 行(row) 数据的基本单元
字段(field) 列(column) 文档中的属性
_id字段 主键(primary key) 每个文档的唯一标识
视图(view) 视图(view) 虚拟集合(3.4+版本支持)
$lookup聚合 表连接(table join) 实现类似连接的功能

关键差异:

  • 半结构化:无需预定义模式,字段可动态增减

  • 弱关系:无外键约束,复杂关联通过聚合管道实现

1.3 技术优势与应用场景

四大核心优势:

  • 开发高效:JSON结构与对象模型接近,代码量低

  • 灵活响应:动态模型轻松适应业务需求变化

  • 高可用:复制集提供99.999%可用性

  • 无缝扩展:分片架构支持海量数据存储

  • 六大应用场景:

  • 游戏:存储用户信息、装备、积分(内嵌文档形式)

  • 物流:订单状态跟踪(内嵌数组记录变更)

  • 社交:用户信息、朋友圈、附近的人(地理位置索引)

  • 物联网:设备信息、日志数据、多维度分析

  • 视频直播:用户信息、礼物信息管理

  • 大数据:云存储系统,实时数据提取分析

  • 决策指南:只要满足以下任一条件,即可考虑使用MongoDB

    • 需要快速迭代开发,数据模式频繁变化

    • 数据具有嵌套的多层次结构

    • 需要处理海量数据和高并发访问

    • 追求高可用性和水平扩展能力

    • 开发团队熟悉JavaScript/JSON技术栈

    二、环境搭建:多平台部署指南

    2.1 Linux系统安装(CentOS 7为例)

    1. 下载与解压

    bash

    # 下载MongoDB 6.0.5
    wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz
    # 解压
    tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz

    2. 目录准备与启动

    bash

    # 创建数据目录和日志目录
    mkdir -p /mongodb/data /mongodb/log
    # 启动服务(后台运行)
    cd mongodb
    bin/mongod –port=27017 –dbpath=/mongodb/data \\
    –logpath=/mongodb/log/mongodb.log \\
    –bind_ip=0.0.0.0 –fork

    关键启动参数:

    • –dbpath:数据文件存储目录

    • –logpath:日志文件路径(必须是文件,不是目录)

    • –bind_ip:绑定IP(0.0.0.0表示监听所有网卡)

    • –fork:后台运行

    • –auth:启用认证模式

    3. 配置文件方式启动 创建 /mongodb/conf/mongo.conf:

    yaml

    systemLog:
    destination: file
    path: /mongodb/log/mongod.log
    logAppend: true
    storage:
    dbPath: /mongodb/data
    engine: wiredTiger
    journal:
    enabled: true
    net:
    bindIp: 0.0.0.0
    port: 27017
    processManagement:
    fork: true

    启动命令:mongod -f /mongodb/conf/mongo.conf

    2.2 MongoDB Shell (mongosh) 使用

    注意:MongoDB 6.0移除了旧的mongo客户端,改用全新的mongosh。

    安装与连接:

    bash

    # CentOS安装mongosh
    wget https://downloads.mongodb.com/compass/mongodb-mongosh-1.8.0.x86_64.rpm
    yum install -y mongodb-mongosh-1.8.0.x86_64.rpm

    # 三种连接方式
    mongosh –host=192.168.65.206 –port=27017
    mongosh 192.168.65.206:27017
    mongosh mongodb://192.168.65.206:27017/test

    常用命令速查:

    javascript

    // 数据库操作
    show dbs // 显示所有数据库
    use test // 切换/创建数据库
    db.dropDatabase() // 删除当前数据库

    // 集合操作
    show collections // 显示所有集合
    db.createCollection("emp") // 创建集合
    db.emp.drop() // 删除集合
    db.emp.stats() // 查看集合详情

    // 其他实用命令
    show users // 显示用户列表
    show roles // 显示角色列表
    load("xxx.js") // 执行JavaScript脚本
    db.help() // 数据库帮助
    db.emp.help() // 集合帮助

    2.3 安全认证配置

    1. 创建管理员用户

    javascript

    // 切换到admin数据库
    use admin
    // 创建root权限用户
    db.createUser({
    user: "fox",
    pwd: "fox",
    roles: ["root"]
    })

    2. 常用权限角色

    • read/readWrite:指定数据库读/写权限

    • dbAdmin:数据库管理函数(索引创建删除等)

    • dbOwner:数据库任意操作权限

    • userAdmin:用户管理权限

    • clusterAdmin:集群管理权限(仅admin库)

    • readWriteAnyDatabase:所有数据库读写权限(仅admin库)

    • root:超级权限(仅admin库)

    3. 启用鉴权启动

    bash

    mongod -f /mongodb/conf/mongo.conf –auth

    4. 认证连接

    bash

    mongosh 192.168.65.206:27017 -u fox -p fox –authenticationDatabase=admin

    2.4 Docker快速部署

    bash

    # 拉取MongoDB 6.0.5镜像
    docker pull mongo:6.0.5

    # 运行容器(启用认证)
    docker run –name mongo-server -p 29017:27017 \\
    -e MONGO_INITDB_ROOT_USERNAME=fox \\
    -e MONGO_INITDB_ROOT_PASSWORD=fox \\
    -d mongo:6.0.5 –wiredTigerCacheSizeGB 1

    # 连接测试
    mongosh ip:29017 -u fox -p fox

    2.5 图形化管理工具推荐

  • MongoDB Compass:官方GUI,免费功能强大

  • Robo 3T:免费开源,轻量级

  • Studio 3T:功能全面,提供30天试用

  • 数据库工具包:包含mongostat(性能监控)、mongotop(热点监控)等命令行工具

  • 三、文档操作:CRUD全解析

    3.1 插入文档

    单条插入:

    javascript

    db.books.insertOne(
    {name: "fox", age: 35},
    {
    writeConcern: {
    w: "majority", // 写入大多数节点
    j: true, // 持久化到磁盘
    wtimeout: 5000 // 5秒超时
    }
    }
    )

    批量插入:

    javascript

    // 生成50条测试数据
    var tags = ["nosql", "mongodb", "document", "developer", "popular"];
    var types = ["technology", "sociality", "travel", "novel", "literature"];
    var books = [];

    for(var i = 0; i < 50; i++) {
    var typeIdx = Math.floor(Math.random() * types.length);
    var tagIdx = Math.floor(Math.random() * tags.length);
    var favCount = Math.floor(Math.random() * 100);

    books.push({
    title: "book-" + i,
    type: types[typeIdx],
    tag: tags[tagIdx],
    favCount: favCount,
    author: "xxx" + i
    });
    }

    // 执行批量插入
    db.books.insertMany(books, {ordered: true}); // ordered: 是否按顺序插入

    // 或者从文件加载
    load("books.js")

    3.2 查询文档

    基础查询:

    javascript

    // 查询所有文档
    db.books.find()
    // 格式化显示
    db.books.find().pretty()
    // 查询单个文档
    db.books.findOne({tag: "nosql"})

    条件查询对照表:

    SQL条件MongoDB查询
    a = 1 {a: 1}
    a ≠ 1 {a: {$ne: 1}}
    a > 1 {a: {$gt: 1}}
    a ≥ 1 {a: {$gte: 1}}
    a < 1 {a: {$lt: 1}}
    a ≤ 1 {a: {$lte: 1}}
    a = 1 AND b = 1 {a: 1, b: 1} 或 {$and: [{a: 1}, {b: 1}]}
    a = 1 OR b = 1 {$or: [{a: 1}, {b: 1}]}
    a IS NULL {a: {$exists: false}}
    a IN (1,2,3) {a: {$in: [1, 2, 3]}}

    正则表达式查询:

    javascript

    // 查询type包含"so"的文档
    db.books.find({type: {$regex: "so"}})
    // 简写方式
    db.books.find({type: /so/})

    排序与分页:

    javascript

    // 按收藏数降序排序
    db.books.find({type: "travel"}).sort({favCount: -1}) // -1:降序,1:升序

    // 分页:每页8条,查询第3页
    db.books.find().skip(16).limit(8) // skip(16)跳过前16条(前两页)

    分页优化技巧:

    javascript

    // 传统分页问题:skip性能差,count数据量大时慢
    // 优化方案:基于_id的连续查询
    var pageSize = 10;

    // 第一页
    var page1 = db.books.find().sort({_id: 1}).limit(pageSize);
    var lastId = page1[page1.length – 1]._id;

    // 第二页(使用上一页最后一条记录的_id)
    var page2 = db.books.find({_id: {$gt: lastId}})
    .sort({_id: 1})
    .limit(pageSize);

    3.3 更新文档

    更新操作符:

    操作符格式描述
    $set {$set: {field: value}} 设置字段值(不存在则创建)
    $unset {$unset: {field: 1}} 删除字段
    $inc {$inc: {field: value}} 数值字段增减
    $rename {$rename: {old: new}} 重命名字段
    $push {$push: {field: value}} 向数组追加元素
    $pull {$pull: {field: value}} 从数组删除元素
    $addToSet {$addToSet: {field: value}} 向数组添加元素(排重)

    更新示例:

    javascript

    // 更新单个文档(收藏数+1)
    db.books.updateOne(
    {_id: ObjectId("642e62ec933c0dca8f8e9f60")},
    {$inc: {favCount: 1}}
    )

    // upsert:不存在则插入
    db.books.updateOne(
    {title: "my book"},
    {$set: {tags: ["nosql", "mongodb"], type: "none", author: "fox"}},
    {upsert: true} // 关键参数
    )

    // 更新多个文档
    db.books.updateMany(
    {type: "novel"},
    {$set: {publishedDate: new Date()}}
    )

    // findAndModify:查询并修改,返回修改前/后的文档
    db.books.findAndModify({
    query: {_id: ObjectId("642ec31813bdda928a1ea2a8")},
    update: {$inc: {favCount: 1}},
    new: true // true:返回修改后,false:返回修改前(默认)
    })

    3.4 删除文档

    javascript

    // 删除单个文档
    db.books.deleteOne({type: "novel"})

    // 删除多个文档
    db.books.deleteMany({type: "novel"})

    // 删除集合所有文档
    db.books.deleteMany({})

    // 高效删除整个集合(比分批删除快)
    db.books.drop()

    // 返回被删除的文档
    db.books.findOneAndDelete(
    {type: "novel"},
    {sort: {favCount: 1}} // 按收藏数升序删除第一个
    )

    3.5 批量操作

    javascript

    // bulkWrite实现批量操作
    db.pizzas.bulkWrite([
    {
    insertOne: {
    document: {_id: 3, type: "beef", size: "medium", price: 6}
    }
    },
    {
    updateOne: {
    filter: {type: "cheese"},
    update: {$set: {price: 8}}
    }
    },
    {
    deleteOne: {filter: {type: "pepperoni"}}
    },
    {
    replaceOne: {
    filter: {type: "vegan"},
    replacement: {type: "tofu", size: "small", price: 4}
    }
    }
    ])

    四、数据类型详解:超越JSON的BSON

    4.1 BSON:MongoDB的二进制JSON

    为什么选择BSON而不是JSON?

  • 更高效的遍历:编码时记录元素长度,支持seek操作直接读取

  • 更丰富的数据类型:扩展了日期、二进制、ObjectId等类型

  • 轻量级语义:保持JSON的简洁性,支持嵌套和数组结构

  • BSON限制:

    • 单个文档最大16MB

    • 嵌套级别不超过100层

    4.2 日期类型

    javascript

    // 创建日期字段(存储为UTC时间)
    db.events.insert({
    name: "发布会",
    date: new Date(), // 方式1:JavaScript Date对象
    created: ISODate() // 方式2:MongoDB ISODate
    })

    // 查询:默认返回的是UTC时间
    db.events.find()

    4.3 ObjectId:分布式唯一标识

    ObjectId结构(12字节=24位十六进制):

    • 4字节:Unix时间戳(秒)

    • 5字节:随机数(机器号+进程号)

    • 3字节:计数器(初始化随机)

    javascript

    // 生成和操作ObjectId
    var id = ObjectId() // 生成新ObjectId
    id.getTimestamp() // 获取创建时间
    id.toString() // 转换为字符串
    id.str // 十六进制字符串表示

    // 客户端通常自动生成_id
    db.collection.insert({name: "test"}) // 自动补充_id字段

    4.4 内嵌文档与数组

    内嵌文档示例:

    javascript

    // 插入包含作者信息的书籍
    db.books.insert({
    title: "撒哈拉的故事",
    author: {
    name: "三毛",
    gender: "女",
    hometown: "重庆"
    }
    })

    // 查询内嵌字段
    db.books.find({"author.name": "三毛"})

    // 更新内嵌字段
    db.books.updateOne(
    {"author.name": "三毛"},
    {$set: {"author.hometown": "重庆/台湾"}}
    )

    数组操作示例:

    javascript

    // 添加标签数组
    db.books.updateOne(
    {"author.name": "三毛"},
    {$set: {tags: ["旅行", "随笔", "散文", "爱情", "文学"]}}
    )

    // 数组末尾追加元素
    db.books.updateOne(
    {"author.name": "三毛"},
    {$push: {tags: "猎奇"}}
    )

    // 批量追加元素
    db.books.updateOne(
    {"author.name": "三毛"},
    {$push: {tags: {$each: ["伤感", "想象力"]}}}
    )

    // 追加后只保留最后3个元素
    db.books.updateOne(
    {"author.name": "三毛"},
    {$push: {tags: {
    $each: ["伤感", "想象力"],
    $slice: -3 // 只保留最后3个
    }}}
    )

    // 数组查询
    db.books.find({tags: "伤感"}) // 包含"伤感"
    db.books.find({tags: {$all: ["伤感", "想象力"]}}) // 同时包含

    复杂数组结构(商品属性示例):

    javascript

    // 商品多属性表示
    db.goods.insertMany([
    {
    name: "羽绒服",
    tags: [
    {tagKey: "size", tagValue: ["M", "L", "XL", "XXL", "XXXL"]},
    {tagKey: "color", tagValue: ["黑色", "宝蓝"]},
    {tagKey: "style", tagValue: "韩风"}
    ]
    },
    {
    name: "羊毛衫",
    tags: [
    {tagKey: "size", tagValue: ["L", "XL", "XXL"]},
    {tagKey: "color", tagValue: ["蓝色", "杏色"]},
    {tagKey: "style", tagValue: "韩风"}
    ]
    }
    ])

    // 数组元素匹配查询
    db.goods.find({
    tags: {
    $elemMatch: {tagKey: "color", tagValue: "黑色"}
    }
    })

    // 组合条件查询
    db.goods.find({
    tags: {
    $all: [
    {$elemMatch: {tagKey: "color", tagValue: "黑色"}},
    {$elemMatch: {tagKey: "size", tagValue: "XL"}}
    ]
    }
    })

    4.5 固定集合:FIFO数据队列

    创建固定集合:

    javascript

    // 创建最多10条文档或4KB大小的固定集合
    db.createCollection("logs", {
    capped: true, // 固定集合
    size: 4096, // 最大4KB(必选)
    max: 10 // 最多10条文档(可选)
    })

    特性与应用:

  • FIFO原则:新文档插入末尾,空间不足时覆盖最旧文档

  • 高性能:写入顺序固定,无需索引维护开销

  • 自动淘汰:无需手动清理旧数据

  • 应用场景:

    • 系统日志存储

    • 实时数据流(如股票价格)

    • 最新N条记录缓存

    股票行情系统示例:

    javascript

    // 1. 创建消息队列集合
    db.createCollection("stock_queue", {
    capped: true,
    size: 10485760 // 10MB容量
    })

    // 2. 创建时间索引
    db.stock_queue.createIndex({timestamp: 1})

    // 3. 生产者模拟(每秒发布股价)
    function pushEvent() {
    while(true) {
    db.stock_queue.insert({
    timestamp: new Date(),
    stock: "MongoDB Inc",
    price: 100 * Math.random(1000)
    });
    print("publish stock changed");
    sleep(1000);
    }
    }

    // 4. 消费者监听(类似tail -f)
    function listen() {
    var cursor = db.stock_queue
    .find({timestamp: {$gte: new Date()}})
    .tailable(); // 创建可追加游标

    while(true) {
    if(cursor.hasNext()) {
    print(JSON.stringify(cursor.next(), null, 2));
    }
    sleep(1000);
    }
    }

    五、Spring Boot整合:Java开发者实践

    5.1 环境配置

    1. Maven依赖

    xml

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

    2. 配置文件(application.yml)

    yaml

    spring:
    data:
    mongodb:
    # URI方式(推荐)
    uri: mongodb://fox:fox@192.168.65.174:27017/test?authSource=admin

    # 拆分方式(等价于上面URI)
    # database: test
    # host: 192.168.65.174
    # port: 27017
    # username: fox
    # password: fox
    # authentication-database: admin

    3. 实体类映射

    java

    @Document("emp") // 对应emp集合
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Employee {

    @Id // 映射为文档_id
    private Integer id;

    @Field("username") // 指定字段名
    private String name;

    @Field // 默认使用字段名
    private int age;

    @Field
    private Double salary;

    @Field
    private Date entryDay;

    @Transient // 不持久化到数据库
    private String tempField;
    }

    5.2 核心操作示例

    1. 集合操作

    java

    @Autowired
    private MongoTemplate mongoTemplate;

    @Test
    public void testCollection() {
    // 检查集合是否存在
    boolean exists = mongoTemplate.collectionExists("emp");

    if (exists) {
    // 删除集合
    mongoTemplate.dropCollection("emp");
    }

    // 创建集合
    mongoTemplate.createCollection("emp");
    }

    2. 文档CRUD

    java

    // 插入文档
    @Test
    public void testInsert() {
    // 插入单条(_id存在时抛异常)
    Employee emp1 = new Employee(1, "小明", 30, 10000.00, new Date());
    mongoTemplate.insert(emp1);

    // 插入多条
    List<Employee> list = Arrays.asList(
    new Employee(2, "张三", 21, 5000.00, new Date()),
    new Employee(3, "李四", 26, 8000.00, new Date()),
    new Employee(4, "王五", 22, 8000.00, new Date())
    );
    mongoTemplate.insert(list, Employee.class);

    // save方法:_id存在时更新
    // mongoTemplate.save(employee);
    }

    // 查询文档
    @Test
    public void testFind() {
    // 查询所有
    List<Employee> all = mongoTemplate.findAll(Employee.class);

    // 根据_id查询
    Employee emp = mongoTemplate.findById(1, Employee.class);

    // 条件查询
    // 薪资>=8000
    Query query1 = new Query(Criteria.where("salary").gte(8000));

    // 薪资>4000且<10000
    Query query2 = new Query(Criteria.where("salary").gt(4000).lt(10000));

    // 模糊查询
    Query query3 = new Query(Criteria.where("name").regex("张"));

    // AND查询:年龄>25且薪资>8000
    Criteria criteria1 = new Criteria();
    criteria1.andOperator(
    Criteria.where("age").gt(25),
    Criteria.where("salary").gt(8000)
    );

    // OR查询:姓名为张三或薪资>5000
    Criteria criteria2 = new Criteria();
    criteria2.orOperator(
    Criteria.where("name").is("张三"),
    Criteria.where("salary").gt(5000)
    );

    // 排序和分页
    Query query = new Query(criteria2)
    .with(Sort.by(Sort.Order.desc("salary"))) // 按薪资降序
    .skip(0) // 跳过0条
    .limit(4); // 每页4条

    List<Employee> result = mongoTemplate.find(query, Employee.class);

    // JSON方式查询
    String json = "{$or: [{age: {$gt: 25}}, {salary: {$gte: 8000}}]}";
    Query jsonQuery = new BasicQuery(json);
    List<Employee> jsonResult = mongoTemplate.find(jsonQuery, Employee.class);
    }

    // 更新文档
    @Test
    public void testUpdate() {
    // 查询条件:薪资>=15000
    Query query = new Query(Criteria.where("salary").gte(15000));

    // 更新操作:薪资设置为13000
    Update update = new Update();
    update.set("salary", 13000);

    // 更新第一条匹配记录
    // UpdateResult result = mongoTemplate.updateFirst(query, update, Employee.class);

    // 更新所有匹配记录
    // UpdateResult result = mongoTemplate.updateMulti(query, update, Employee.class);

    // upsert:不存在则插入
    update.setOnInsert("id", 11); // 指定插入时的_id
    UpdateResult result = mongoTemplate.upsert(query, update, Employee.class);

    System.out.println("修改记录数:" + result.getModifiedCount());
    }

    // 删除文档
    @Test
    public void testDelete() {
    // 删除所有文档
    // mongoTemplate.remove(new Query(), Employee.class);

    // 条件删除:薪资<10000
    Query query = new Query(Criteria.where("salary").lt(10000));
    mongoTemplate.remove(query, Employee.class);
    }

    5.3 高级配置:去除_class属性

    Spring Data MongoDB默认会在文档中添加_class字段存储Java类全限定名,可通过以下配置去除:

    java

    @Configuration
    public class MongoConfig {

    @Bean
    public MappingMongoConverter mappingMongoConverter(
    MongoDatabaseFactory mongoDatabaseFactory,
    MongoMappingContext context,
    MongoCustomConversions conversions) {

    DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDatabaseFactory);
    MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, context);
    converter.setCustomConversions(conversions);

    // 关键配置:设置TypeMapper,去除_class字段
    converter.setTypeMapper(new DefaultMongoTypeMapper(null));

    return converter;
    }
    }

    六、MongoDB 6.0 新特性概览

  • 时序集合增强:更好的时间序列数据处理能力

  • Change Stream增强:更强大的实时数据变更监听

  • 可查询加密:客户端字段级加密,提升数据安全

  • 聚合&查询能力增强:更丰富的聚合管道操作符

  • 集群同步优化:改进的集群数据同步机制

  • 七、最佳实践总结

    7.1 设计原则

  • 适度反规范化:合理使用内嵌文档减少查询次数

  • 预聚合常用数据:避免实时计算开销

  • 索引策略:为查询字段创建索引,但避免过度索引

  • 写关注配置:根据业务需求调整writeConcern级别

  • 7.2 性能优化

  • 分页优化:避免使用skip进行深度分页

  • 投影优化:只查询需要的字段

  • 批量操作:使用bulkWrite减少网络往返

  • 连接池管理:合理配置连接池参数

  • 7.3 监控与维护

  • 定期检查慢查询:使用数据库Profiler

  • 监控硬件资源:CPU、内存、磁盘IO

  • 备份策略:定期备份,测试恢复流程

  • 版本升级:测试环境先行,生产环境分批升级

  • 赞(0)
    未经允许不得转载:171主机测评 » MongoDB 6.0 从入门到整合:一份面向Java开发者的实战指南
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址