【MongoDB】认识NoSQL,与MongoDB在SpringBoot框架下的文件存储

 随着互联网应用变得越来越复杂,数据格式越来越灵活,我们常常会遇到这样的困境:

  • 需求频繁变更:增加一个字段就要改表结构(ALTER TABLE),在海量数据上这简直是噩梦。

  • 数据结构复杂:想存储一个嵌套的JSON对象,得拆分成十几张表,查询时要写复杂的JOIN,性能堪忧。

正是为了解决这些问题,NoSQL数据库应运而生,而MongoDB便是其中之一。

一、什么是NoSQL?

NoSQL 的全称是 Not Only SQL,意为“不仅仅是SQL”。它并不是要取代SQL,而是为其提供一种补充,适用于不同的场景。

NoSQL数据库种类繁多,主要分为以下几类:

  • 文档型数据库:如 MongoDB(以灵活的JSON-like文档存储数据)

  • 键值型数据库:如 Redis(简单的键值对,速度极快)

  • 列族数据库:如 Cassandra(为大规模数据分析设计)

  • 图数据库:如 Neo4j(专注于实体之间的关系)

它们的共同特点是:灵活、易扩展、高性能

二、什么是MongoDB?

关于MongoDB的介绍、安装,具体内容详见下述文章:

01 MongoDB的概述、应用场景、下载方式、连接方式和发展历史等-阿里云开发者社区https://developer.aliyun.com/article/1611979

MongoDB与Reids的差异:

特性MongoDBRedis
核心定位文档型数据库内存型键值数据库
数据模型丰富的 文档模型 (类似 JSON的BSON)简单的 键值对,值支持多种数据结构
存储介质磁盘 (内存用于缓存加速)内存 (可持久化到磁盘)
主要优势灵活性查询能力海量数据存储速度 (极低延迟)、高并发原子操作
典型用例主数据库、内容管理、用户配置、实时分析缓存、消息队列、会话存储、实时排行榜

三、与Mysql对比进行MongoDB的理解

概念对比

概念MongoDB (文档数据库)MySQL (关系型数据库)
数据格式类似JSON的文档(灵活嵌套)表格(严格的行和列)
例子{_id: 1, name: "Alice", hobbies: ["唱歌", "游泳"] }id: 1, name: "Alice" (hobbies需拆到另一张表)
适合场景数据结构多变、嵌套复杂(如用户画像、日志)结构固定、需要强一致性(如订单、账户)

术语对比

MySQL 术语MongoDB 对应术语区别说明
数据库 (Database)数据库 (Database)概念相同
表 (Table)集合 (Collection)MySQL 表有固定结构,MongoDB 集合无固定结构
行 (Row)文档 (Document)MongoDB 的文档可以嵌套其他文档或数组
列 (Column)字段 (Field)MongoDB 的字段可以动态增减
主键 (Primary Key)_id 字段MongoDB 自动生成唯一 _id
外键 (Foreign Key)无原生支持MongoDB 通过手动引用实现关联
JOIN 操作$lookup(有限支持)MongoDB 的关联查询性能较低,推荐数据嵌套

查询语法对比

查询类型MySQL 查询语句MongoDB 查询语句
查询所有用户SELECT * FROM users;db.users.find();
条件查询(年龄>18)SELECT * FROM users WHERE age > 18;db.users.find([ age: { $gt: 18 } ]);
关联查询(用户+订单)SELECT u.name, o.order_id FROM users u JOIN orders o ON u.id = o.user_id;db.users.aggregate([ { $lookup: { from: "orders", localField: "_id", foreignField: "user_id", as: "orders" } } ]);

四、MongoDB + Spring Boot 实现文件存储

(一)两种存储方式

MongoDB 提供两种文件存储方式:

1. GridFS

  • 适合大文件(>16MB,MongoDB 单个文档限制)
  • 自动分块存储,支持流式读写

2. 直接存储小文件(Base64/Binary

  • 适合小文件(<16MB)
  • 简单快捷,无需额外配置

以下采用GridFS大文件存储的方式,进行文件存储。

(二)添加依赖与配置文件

<!-- mongodb依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
# application.yml
spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: test
      # username: your_user
      # password: your_pass

(三)代码实践

需在controller类中添加

import org.springframework.data.mongodb.core.MongoTemplate;
    @Autowired
    private MongoTemplate mongoTemplate;
    // 对mongo数据库进行连接使用
文件上传
@PostMapping("upload")
    public String uploadFile(MultipartFile file) {
        try (InputStream inputStream = file.getInputStream()){

            // 1、 创建桶(数据库名称 ,桶名 )
            GridFSBucket bucket = GridFSBuckets.create(mongoTemplate.getDb(),"file");

            //2、 设置分片上传的条件
            GridFSUploadOptions options = new GridFSUploadOptions()
                    .chunkSizeBytes(1024)
                    .metadata(new Document("filename",file.getOriginalFilename()));  // 附加的记录信息

            // 3、 上传文件
            // objectId 是 文件的唯一标识 ( mongodb集合中的主键  “_id”)
            ObjectId objectId = bucket.uploadFromStream(file.getOriginalFilename(), inputStream,options);
            // 转化成String
            return objectId.toHexString();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
文件预览/下载
    @GetMapping("preview/{id}")
    public void previewFile(@PathVariable("id") String id, HttpServletResponse response) {

        // 1、 创建桶
        GridFSBucket bucket = GridFSBuckets.create(mongoTemplate.getDb(),"file");

        // 2、 获取文件主键信息
        ObjectId objectId = new ObjectId(id);

        // 3、 查找文件信息
        // 查找条件 new BsonDocument("_id", new BsonObjectId(objectId))
        GridFSFile file = bucket
                .find(new BsonDocument("_id", new BsonObjectId(objectId)))
                .first();

        if (file == null) {
//            throw new RuntimeException("文件不存在");
            try {
                response.sendError(40404,"文件不存在");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        // 文件存在 ,获取文件流
        // 4、 获取文件流
        // 设置响应头(根据文件类型调整 Content-Type)
        //response.setContentType(file.getMetadata().get("_contentType", "application/octet-stream"));
        response.setHeader("Content-Disposition", "inline; filename=\"" + file.getFilename() + "\"");

        // 5 、将文件流写入响应
        try (GridFSDownloadStream downloadStream = bucket.openDownloadStream(file.getObjectId())) {
            try {
                IOUtils.copy(downloadStream, response.getOutputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
文件删除
    @DeleteMapping("/delete/{id}")
    public void delete(@PathVariable String id) {
        GridFSBucket bucket = GridFSBuckets.create(mongoTemplate.getDb(),"file");

        bucket.delete(new ObjectId(id));
    }
存在判断
@GetMapping("/{id}")
    public String get(@PathVariable String id) {
        // 1、 创建桶
        GridFSBucket bucket = GridFSBuckets.create(mongoTemplate.getDb(),"file");
        // 2、 查找文件信息  查找条件 new BsonDocument("_id", new BsonObjectId(objectId))
        GridFSFile file = bucket
                .find(new BsonDocument("_id", new BsonObjectId(new ObjectId(id))))
                .first();

        if (file != null) {
            return "文件存在";
        } else {
            return "文件不存在";
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值