MongoDB 与 mysql 相比的缺陷

MongoDB 与 mysql 同属于开源阵列,但相较于 mysql,MongoDB 日常项目中接触的不多。但 MongoDB 有它独特的优势,属于 NoSQL 类型的数据库,比较适用于分布式扩展以及大数据运算。

网上提到 MongoDB 主要存在的缺陷:不支持 join 联查,不支持事务操作。MongoDB 的存储单元不同于 mysql 的表,它使用的是 Collection 集合,存储的也不是一行一行的字段数据,而是一个一个的 Document 文档。所以不支持 join 很正常,但 MongoDB 可以通过 lookup 实现多表联查。至于事务操作,百度到也是有其他的实现方式的,比如 SpringBoot @Transactional 注解。

MongoDB 的漏洞

MongoDB 最近(2022年11月)有被爆出存在关键漏洞(CVE-2022-40299),这个漏洞可能允许未授权的攻击者远程执行代码。

MongoDB 最近爆出的漏洞

漏洞本身升级最新的版本就可以了。并且也通过防火墙规则限制,只允许业务服务器访问,提高安全性。

安装 MongoDB

因为本地 Mac 环境按装了 docker 桌面版,所以优先使用 docker 安装 MongoDB。安装参考:Docker基础:docker 安装mongodb - 腾讯云社区

docker pull mongo[:latest]

后面的 :lastest 可以不加,因为默认就是拉取最新版本。

之后运行镜像容器:

docker run \
-dit \
--name mongo \
--restart=always \
--privileged=true \
-p 27017:27017 \
-v /Users/mac/docker/mongodb/data:/data/db \
mongo:latest --auth

因为 docker 桌面版直接运行容器没办法携带这些参数,所以就从命令行执行,之后再 docker 桌面版容器里可以看到管理启动与停止。

-d 表示以守护进程方式运行,-i 表示以交互模式运行容器,-t 表示为容器分配一个伪终端(pseudo-tty)。-it 这两个参数一起使用可以使得在容器内部进行交互式操作,就像在本地终端中一样。
--name mongo 表示指定容器名称。
--restart=always 表示启动失败后会一直自动重启。
-p 27017:27017表示将容器的 27017 端口映射到宿主机的 27017 端口,以便外部访问。
-v /Users/mac/docker/mongodb/data:/data/db 表示将容器的 /data/db 数据存储文件目录映射到宿主机的 /Users/mac/docker/mongodb/data 目录。宿主机目录在前,可以根据本地环境自定义,:分隔两个目录。
--auth表示访问 MongoDB 需要用户名和密码。

之后可以通过命令行 docker exec -it mongo /bin/bash 进入容器,也可以桌面版找到 mongo 容器,进入详情,切换到 Exec 容器命令行。

可以使用 mongod --version 查看安装的 mongoDB 版本,当前安装的是 v7.0.7 版本。

登录 mongoDB 的指令发生了变化,不再是 mongo admin,会报错找不到 mongo 指令。新版为 mongosh admin,在原指令名称上加了 sh 表示 mongo shell 脚本。这里的 admin 是数据库的名称。授权逻辑发生了变化,mysql 是需要先验证身份,之后访问数据库;mongo 是先连接到数据库,之后再做身份验证。

# mongosh admin
Current Mongosh Log ID: 65fbd627b4034fafbfdb83af
Connecting to:          mongodb://127.0.0.1:27017/admin?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.2.0
Using MongoDB:          7.0.7
Using Mongosh:          2.2.0

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

admin> 

首次登录是没有账号密码的,需要创建一下:

# 创建一个名为 root,密码为 123456 的用户。猜测后面的角色权限参数应该是给到所有数据库的读写权限。
admin> db.createUser({ user:'root',pwd:'123456',roles:[{ role:'userAdminAnyDatabase', db: 'admin'},"readWriteAnyDatabase"]});

有了 auth 账户,下次再连接数据库,操作 Collection 集合就需要先验证身份了。不然操作会报错:MongoServerError[Unauthorized]: Command createUser requires authentication

admin> db.auth('root', '123456')
{ ok: 1 }

创建集合(表):

db.createCollection('users')

插入数据:

admin> db.users.insert({"name":"小李","age": NumberInt(33)})

查看数据:

admin> db.users.find()

之后就是使用 Navicat 连接 MongoDB 了:

使用 Navicat 连接 MongoDB

输入连接主机、端口,以及账号密码都没有问题,主要是第一次连接 MongoDB,Navicat 默认会隐藏数据库内容,需要从菜单栏点击查看,勾选显示隐藏的项目

默认会有三个数据库:admin、config、local,后面两个需要权限才能打开。admin 中应该会有三个表:system.users 系统用户表,上面添加的 root 账号就存储在这里;system.version 系统版本表,以及上面创建的 users 测试表。

搭建 SpringBoot 项目

摘录百度 AI 生成的回答

1. 添加 Maven 依赖

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

因为属于 spring-boot-starter 的版本,所以会根据引入的 spring boot 版本中依赖版本默认安装。其他依赖根据需求自行选择。

2. 配置 MongoDB

在application.properties中添加以下配置:

spring.data.mongodb.uri=mongodb://username:password@localhost:27017/your_database

或者,如果你使用application.yml:

spring:
  data:
    mongodb:
      uri: mongodb://username:password@localhost:27017/your_database

3. 创建实体类

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
 
@Document
public class YourEntity {
    @Id
    private String id;
    // 其他字段和方法
}

与 mysql 的实体主要在于注解,这里使用的是 @Document

4. 创建MongoDB仓库接口

import org.springframework.data.mongodb.repository.MongoRepository;
 
public interface YourEntityRepository extends MongoRepository<YourEntity, String> {
    // 可以自定义查询方法
}

这边也是继承的 repo 不一样。看到还有一种 MongoTemplate 的使用方法,区别在于 template 可以处理更加复杂的查询,比如联合查询等。具体可以查看:SpringBoot中MongoDB的使用 - CSDN

5. 使用仓库进行操作

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service
public class YourEntityService {
 
    @Autowired
    private YourEntityRepository repository;
 
    public YourEntity save(YourEntity entity) {
        return repository.save(entity);
    }
 
    public YourEntity findById(String id) {
        return repository.findById(id).orElse(null);
    }
 
    // 其他方法
}