MongoDB安装、 技术选型、应用、数据迁移

一、MongoDB简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构

非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点

类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。MongoDB服务端可

运行在Linux、Windows或mac os x平台,支持32位和64位应用,默认端口为27017。推荐运行在64位平台,因为MongoDB在32位模式

运行时支持的最大文件尺寸为2GB。

​ 在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。

MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

在这里插入图片描述

结构

集合

集合就是一组文档,类似于关系数据库中的表。

数据库

MongoDB中多个文档组成集合,多个集合组成数据库。

数据模型

一个MongoDB 实例可以包含一组数据库,一个DataBase 可以包含一组Collection(集合),一个集合可以包含一组Document(文档)。
一个Document包含一组field(字段),每一个字段都是一个key/value pair

  • key: 必须为字符串类型。

  • value:可以包含如下类型。

    • 基本类型,例如,string,int,float,timestamp,binary 等类型。
    • 一个document。
    • 数组类型。

二、主要特点

  • MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。
  • 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName=“Sameer”,Address=“8 Gandhi Road”)来实现更快的排序。
  • 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。
  • 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。
  • Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
  • MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
  • Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
  • Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
  • Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
  • GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
  • MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
  • MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
  • MongoDB安装简单。
  • 支持的系统Linux,OSX,Solaris,Windows

三、为何选择MongoDB

优点

不存在sql注入、不需要提前创建表、可以任意添加或减少字段、字段数据格式自由、可以处理json结构

可以使用upsert操作,即修改的数据不存在时直接插入。

充分利用了计算机内存,所以查询和插入效率要远大于MySQL。(400w随机数据)的时候只有在没有索引的情况下MongoDB的查询效率要远大于MySQL,插入效率和MySQL差不多都是8w条左右1分钟。在有索引的时候MySQL的查询要速度要高于MongoDB。

缺点

MongoDB是个nosql数据,所以关系能力薄弱,不能像MySQL一样使用join,union来进行联合查找,只能通过结合一些特殊语法来达到类似的结果。

事务能力薄弱,虽然MongoDB里事务,但是好像只能针对单条语句(查了好多但是有些看不懂),不能像MySQL一样利用事务执行多条语句,可以根据情况来选着全部提交执行或者全部取消回滚。

相比MySQL,MongoDB的效率存在一定的波动性,不是很稳定。

总结

总结起来,如果你的业务满足一个或多个特点,那么选择MongoDB是个正确的决定:

  • 无需要跨文档或跨表的事务及复杂的join查询支持 // 目前已经支持事务,join的支持也越来越好。

  • 敏捷迭代的业务,需求变动频繁,数据模型无法确定

  • 存储的数据格式灵活,不固定,或属于半结构化数据

  • 业务并发访问量大,需数千的QPS

  • TB级以上的海量数据存储,且数据量不断增加

  • 要求存储的数据持久化、不丢失

  • 需要99.999%的数据高可用性

  • 需要大量的地理位置查询、文本查询

​ 除了MongoDB之外,唯一的著名文档型数据库就是Apache CouchDB。尽管CouchDB的数据是使用JSON格式的纯文本存储的,而MongoDB使用的是BSON二进制格式,但两者的文档模型是相似的。与MongoDB一样,CouchDB也支持二级索引,不同之处是CouchDB中的索引是通过编写MapReduce函数来定义的,这比MySQL和MongoDB使用的声明式语法更复杂一些。两者伸缩的方式也有所不同,CouchDB不会把数据分散到多台服务器上,每个CouchDB节点都是其他节点的完整副本。

​ 目前开源数据库众多,大家可选的余地很大,就会出现这样的问题:MySQL、MongoDB、Redis、Hbase等这些数据库哪个更好?其实这是一个伪命题,脱离了具体的业务场景来讨论好坏是纸上谈兵,没有最好的,只有最合适的,谁也无法保证完全取代谁,上面的每种数据库都在变得更好,都在不停地完善自身。比如MySQL在不断提升其JSON和地理位置处理能力、组复制(group replication)已在开发等;而MongoDB在增强join类型支持,提供更为复杂的多集合查询能力,计划支持事务等;Redis也加入了地理位置处理能力。

四、安装mongo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lfQlc2Dc-1609209485333)(file:///C:/Users/CP-CUI/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)]

登录完之后,

1.创建 admin

角色:userAdminAnyDatabase (这是一个账号管理员的角色)

admin用户用于管理账号,不能进行关闭数据库等操作,目标数据库是admin

创建用户名密码:

use admin
db.createUser({
    "user":"ueh","pwd":"abc123ABC",
    "roles":[
        {role:"userAdminAnyDatabase", db: "admin"}, 
        {role:"readWriteAnyDatabase", db: "admin"} ]});

db.system.users.find()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FWastW7T-1609209485335)(file:///C:/Users/CP-CUI/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg)]

2.创建root

创建完admin管理员,创建一个 超级管理员 root 角色:root

root角色用于 关闭数据库 db.shutdownServer()

db.createUser({user: “root”,pwd: “root123”,roles: [ { role: “root”, db: “admin” } ]})

3.创建用户自己的数据库的角色

当账号管理员和超级管理员,可以为自己的数据库创建用户了

(坑)这时候一定,一定要切换到所在数据库上去创建用户,不然创建的用户还是属于admin。

use ebip

db.createUser({user: “ueh”,pwd: “abc123ABC”,roles: [ { role: “readWrite”, db: “ebip” } ]})

4、配置注册表 使密码生效

5、启动

进入cmd

cd C:\Program Files\MongoDB\Server\4.4\bin

启动服务建立连接执行 : mongod

重新打开一个cmd :

cd C:\Program Files\MongoDB\Server\4.4\bin

执行命令
mongo

测试是否启动成功show dbs

连接远程mongodb

进入mongodb安装目录 执行 mongo ip:27017/数据库 -u 用户名 -p 密码

五、基本应用

1、添加依赖

依赖下载

      <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>3.0.4</version>
        </dependency>
2、连接数据库

连接数据库,你需要指定数据库名称,如果指定的数据库不存在,mongo会自动创建数据库。

连接数据库的Java代码如下:

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
       // 连接到 mongodb 服务
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
       
         // 连接到数据库
         MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
       System.out.println("Connect to database successfully");
        
      }catch(Exception e){
        System.err.println( e.getClass().getName() + ": " + e.getMessage() );
     }
   }
}

使用配置连接

  • application.yml
spring:
  data:
    mongodb:
       uri: mongodb://<username>:<password>@ip:27017/test

本实例中 Mongo 数据库无需用户名密码验证。如果你的 Mongo 需要验证用户名及密码,可以使用以下代码:

import java.util.ArrayList;  
import java.util.List;  
import com.mongodb.MongoClient;  
import com.mongodb.MongoCredential;  
import com.mongodb.ServerAddress;  
import com.mongodb.client.MongoDatabase;  
  
public class MongoDBJDBC {  
    public static void main(String[] args){  
        try {  
            //连接到MongoDB服务 如果是远程连接可以替换“localhost”为服务器所在IP地址  
            //ServerAddress()两个参数分别为 服务器地址 和 端口  
            ServerAddress serverAddress = new ServerAddress("localhost",27017);  
            List<ServerAddress> addrs = new ArrayList<ServerAddress>();  
            addrs.add(serverAddress);  
              
            //MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码  
            MongoCredential credential = MongoCredential.createScramSha1Credential("username", "databaseName", "password".toCharArray());  
            List<MongoCredential> credentials = new ArrayList<MongoCredential>();  
            credentials.add(credential);  
              
            //通过连接认证获取MongoDB连接  
            MongoClient mongoClient = new MongoClient(addrs,credentials);  
              
            //连接到数据库  
            MongoDatabase mongoDatabase = mongoClient.getDatabase("databaseName");  
            System.out.println("Connect to database successfully");  
        } catch (Exception e) {  
            System.err.println( e.getClass().getName() + ": " + e.getMessage() );  
        }  
    }  
} 
3、创建集合

我们可以使用 com.mongodb.client.MongoDatabase 类中的createCollection()来创建集合

代码片段如下:

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
      // 连接到 mongodb 服务
      MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
      // 连接到数据库
      MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
      System.out.println("Connect to database successfully");
      mongoDatabase.createCollection("test");
      System.out.println("集合创建成功");
        
      }catch(Exception e){
        System.err.println( e.getClass().getName() + ": " + e.getMessage() );
     }
   }
}

编译运行以上程序,输出结果如下:

Connect to database successfully
集合创建成功
4、获取集合

我们可以使用com.mongodb.client.MongoDatabase类的 getCollection() 方法来获取一个集合

代码片段如下:

import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
       // 连接到 mongodb 服务
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
       
         // 连接到数据库
         MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
       System.out.println("Connect to database successfully");
      
       MongoCollection<Document> collection = mongoDatabase.getCollection("test");
       System.out.println("集合 test 选择成功");
      }catch(Exception e){
        System.err.println( e.getClass().getName() + ": " + e.getMessage() );
     }
   }
}

编译运行以上程序,输出结果如下:

Connect to database successfully
集合 test 选择成功
5、插入文档

我们可以使用com.mongodb.client.MongoCollection类的 insertMany() 方法来插入一个文档

代码片段如下:

import java.util.ArrayList;
import java.util.List;
import org.bson.Document;
 
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 连接到 mongodb 服务
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         
         // 连接到数据库
         MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
         System.out.println("Connect to database successfully");
         
         MongoCollection<Document> collection = mongoDatabase.getCollection("test");
         System.out.println("集合 test 选择成功");
         //插入文档  
         /** 
         * 1. 创建文档 org.bson.Document 参数为key-value的格式 
         * 2. 创建文档集合List<Document> 
         * 3. 将文档集合插入数据库集合中 mongoCollection.insertMany(List<Document>) 插入单个文档可以用 mongoCollection.insertOne(Document) 
         * */
         Document document = new Document("title", "MongoDB").  
         append("description", "database").  
         append("likes", 100).  
         append("by", "Fly");  
         List<Document> documents = new ArrayList<Document>();  
         documents.add(document);  
         collection.insertMany(documents);  
         System.out.println("文档插入成功");  
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}

编译运行以上程序,输出结果如下:

Connect to database successfully
集合 test 选择成功
文档插入成功
6、检索所有文档

我们可以使用 com.mongodb.client.MongoCollection 类中的 find() 方法来获取集合中的所有文档。

此方法返回一个游标,所以你需要遍历这个游标。

代码片段如下:

import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 连接到 mongodb 服务
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         
         // 连接到数据库
         MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
         System.out.println("Connect to database successfully");
         
         MongoCollection<Document> collection = mongoDatabase.getCollection("test");
         System.out.println("集合 test 选择成功");
         
         //检索所有文档  
         /** 
         * 1. 获取迭代器FindIterable<Document> 
         * 2. 获取游标MongoCursor<Document> 
         * 3. 通过游标遍历检索出的文档集合 
         * */  
         FindIterable<Document> findIterable = collection.find();  
         MongoCursor<Document> mongoCursor = findIterable.iterator();  
         while(mongoCursor.hasNext()){  
            System.out.println(mongoCursor.next());  
         }  
      
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}

编译运行以上程序,输出结果如下:

Connect to database successfully
集合 test 选择成功
Document{{_id=56e65fb1fd57a86304fe2692, title=MongoDB, description=database, likes=100, by=Fly}}
7、更新文档

你可以使用 com.mongodb.client.MongoCollection 类中的 updateMany() 方法来更新集合中的文档。

代码片段如下:

import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 连接到 mongodb 服务
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
         
         // 连接到数据库
         MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
         System.out.println("Connect to database successfully");
         
         MongoCollection<Document> collection = mongoDatabase.getCollection("test");
         System.out.println("集合 test 选择成功");
         
         //更新文档   将文档中likes=100的文档修改为likes=200   
         collection.updateMany(Filters.eq("likes", 100), new Document("$set",new Document("likes",200)));  
         //检索查看结果  
         FindIterable<Document> findIterable = collection.find();  
         MongoCursor<Document> mongoCursor = findIterable.iterator();  
         while(mongoCursor.hasNext()){  
            System.out.println(mongoCursor.next());  
         }  
      
      }catch(Exception e){
         System.err.println( e.getClass().getName() + ": " + e.getMessage() );
      }
   }
}

编译运行以上程序,输出结果如下:

Connect to database successfully
集合 test 选择成功
Document{{_id=56e65fb1fd57a86304fe2692, title=MongoDB, description=database, likes=200, by=Fly}}
8、删除第一个文档

要删除集合中的第一个文档,首先你需要使用com.mongodb.DBCollection类中的 findOne()方法来获取第一个文档,然后使用remove 方法删除。

代码片段如下:

import org.bson.Document;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
 
public class MongoDBJDBC{
   public static void main( String args[] ){
      try{   
         // 连接到 mongodb 服务
         MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
 
         // 连接到数据库
         MongoDatabase mongoDatabase = mongoClient.getDatabase("mycol");  
         System.out.println("Connect to database successfully");
 
         MongoCollection<Document> collection = mongoDatabase.getCollection("test");
         System.out.println("集合 test 选择成功");
 
         //删除符合条件的第一个文档  
         collection.deleteOne(Filters.eq("likes", 200));  
         //删除所有符合条件的文档  
         collection.deleteMany (Filters.eq("likes", 200));  
         //检索查看结果  
         FindIterable<Document> findIterable = collection.find();  
         MongoCursor<Document> mongoCursor = findIterable.iterator();  
         while(mongoCursor.hasNext()){  
           System.out.println(mongoCursor.next());  
         }  
           
      }catch(Exception e){
        System.err.println( e.getClass().getName() + ": " + e.getMessage() );
     }
   }
}

进阶

mongoTemplate

mongoTempate对mongodb的CURD做了封装,使操作和使用变得更加简单方便。

更多接口参见

常用方法
mongoTemplate.findAll(Student.class): 查询Student文档的全部数据
mongoTemplate.findById(<id>, Student.class): 查询Student文档id为id的数据
mongoTemplate.find(query, Student.class);: 根据query内的查询条件查询
mongoTemplate.upsert(query, update, Student.class): 修改
mongoTemplate.remove(query, Student.class): 删除
mongoTemplate.insert(student): 新增

Query对象
1 创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)
2 精准条件:criteria.and(“key”).is(“条件”)
模糊条件:criteria.and(“key”).regex(“条件”)
3、封装条件:query.addCriteria(criteria)
4、大于(创建新的criteria):Criteria gt = Criteria.where(“key”).gt(“条件”)
小于(创建新的criteria):Criteria lt = Criteria.where(“key”).lt(“条件”)
5、Query.addCriteria(new Criteria().andOperator(gt,lt));
6、一个query中只能有一个andOperator()。其参数也可以是Criteria数组。
7、排序 :query.with(new Sort(Sort.Direction.ASC, “age”). and(new Sort(Sort.Direction.DESC, “date”)))

  • 实体类
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
 
import java.time.LocalDateTime;
 
@Data
@Document("student")
public class Student{
    private String id;
    private String username;
    private String password;
    private int age;
    private String gender;
    private LocalDateTime createTime;
}
  • 实现
package com.fzy.javastudy.java.day_0906.service;
 
import com.fzy.javastudy.java.day_0906.model.*;
import com.fzy.javastudy.spring.apimodel.*;
import com.fzy.javastudy.spring.config.ServiceException;
import com.fzy.javastudy.spring.config.SystemException;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.util.List;
import java.util.regex.Pattern;
 
/**
 * https://blog.csdn.net/sinat_35821285/article/details/83511203
 */
@Slf4j
@Service
public class MongoService {
 
    @Resource
    private MongoTemplate mongoTemplate;
 
    /**
     * 查询全部
     *
     * @return ApiResponse
     */
    public ApiResponse findStudents() {
        mongoTemplate.dropCollection(Customer.class);
        List<Student> students = mongoTemplate.findAll(Student.class);
        System.out.println(students);
        long count = mongoTemplate.count(new Query().with(new Sort(Sort.Direction.ASC, "username")), Student.class);
        return Api.ok(students, String.format("%s%d%s", "查询到", count, "条"));
    }
 
    /**
     * 根据id查询
     *
     * @param id _id
     * @return ApiResponse
     */
    public ApiResponse findStudentByID(String id) {
        Student student = mongoTemplate.findById(id, Student.class);
        return Api.ok(student);
    }
 
    /**
     * 准确查询
     *
     * @param student Student对象
     * @return ApiResponse
     */
    public ApiResponse findStudentListByMany(Student student) {
        Query query = new Query(Criteria
                .where("username").is(student.getUsername())
                .and("gender").is(student.getGender())
                .and("age").gt(student.getAge()));
        List<Student> students = mongoTemplate.find(query, Student.class);
        return Api.ok(students);
    }
 
    /**
     * 模糊查询
     * 模糊查询以 【^】开始 以【$】结束 【.*】相当于Mysql中的%
     *
     * @param username 用户名
     * @return ApiResponse
     */
    public ApiResponse findStudentsLikeName(String username) {
        String regex = String.format("%s%s%s", "^.*", username, ".*$");
        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        Query query = new Query(Criteria.where("username").regex(pattern));
        List<Student> students = mongoTemplate.find(query, Student.class);
        return Api.ok(students);
    }
 
    /**
     * 分页查询
     *
     * @param request
     * @return
     */
    public PageApiResponse findStudentsPage(StudentRequest request) {
        try {
            Query query = new Query();
            if (StringUtils.isNotEmpty(request.getUsername())) {
                String regex = String.format("%s%s%s", "^.*", request.getUsername(), ".*$");
                Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
                query.addCriteria(Criteria.where("username").regex(pattern));
            }
            int totalCount = (int) mongoTemplate.count(query, Student.class);
            List<Student> studentList = mongoTemplate.find(query.skip(request.getOffset()).limit(request.getPageSize()), Student.class);
            PageApiResponse response = PageApi.ok(studentList, totalCount, "获取列表成功");
            response.setTotalPage(PageCounter.toTalPage(totalCount, request.getPageSize()));
            response.handleRequest(request);
            return response;
        } catch (Exception e) {
            throw new SystemException(-1, "获取分页数据出错");
        }
    }
 
    /**
     * 修改
     * @param student Student
     * @return ApiResponse
     */
    public ApiResponse updateStudent(Student student) {
        try {
            Query query = new Query(Criteria.where("_id").is(student.getId()));
            Update update = new Update();
            update.set("username", student.getUsername());
            update.set("password", student.getPassword());
            update.set("age", student.getAge());
            update.set("gender", student.getGender());
            UpdateResult result = mongoTemplate.upsert(query, update, Student.class);
            long count = result.getModifiedCount();
            if (count > 0) {
                return Api.ok(null, "更新成功");
            }
            throw new ServiceException(-1, "更新失败");
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SystemException(-1, "更新出错");
        }
    }
 
    /**
     * 删除
     * @param id id
     * @return ApiResponse
     */
    public ApiResponse delete(String id) {
        try {
            Query query = new Query(Criteria.where("_id").is(id));
            DeleteResult result = mongoTemplate.remove(query, Student.class);
            long count = result.getDeletedCount();
            if (count > 0) {
                return Api.ok(count, "删除成功");
            }
            throw new ServiceException(-1, String.format("【%s】%s", id, "不存在"));
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            throw new SystemException(-1, "删除出错");
        }
    }
 
    /**
     * 新增
     *
     * @param student
     * @return
     */
    public ApiResponse createStudent(Student student) {
        try {
            Student insert = mongoTemplate.insert(student);
            return Api.ok(insert);
        } catch (Exception e) {
            e.printStackTrace();
            throw new SystemException(-1, "创建出错");
        }
    }
}
GridFS

相关连接

GridFS是Mongo的一个子模块,使用GridFS可以基于MongoDB来持久存储文件。并且支持**分布式应用(**文件分布存储和读取)。作为

MongoDB中二进制数据存储在数据库中的解决方案,通常用来处理大文件,对于MongoDB的BSON格式的数据(文档)存储有尺寸限制,

最大为16M。但是在实际系统开发中,上传的图片或者文件可能尺寸会很大,此时我们可以借用GridFS来辅助管理这些文件

GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。

GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。

GridFS 可以更好的存储大于16M的文件。

GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。

GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。

每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。

使用场景

▲如果您的文件系统在一个目录中存储的文件的数量有限,你可以使用GridFS存储尽可能多的文件。

▲当你想访问大型文件的部分信息,却不想加载整个文件到内存时,您可以使用GridFS存储文件,并读取文件部分信息,而不需要加载整个文件到内存。

▲当你想让你的文件和元数据自动同步并部署在多个系统和设施,你可以使用GridFS实现分布式文件存储。

GridFS不是MongoDB自身特性,只是一种将大型文件存储在MongoDB的文件规范,所有官方支持的驱动均实现了GridFS规范。GridFS制定大文件在数据库中如何处理,通过开发语言驱动来完成、通过API接口来存储检索大文件。

以下是简单的 fs.files 集合文档:

{
   "filename": "test.txt",
   "chunkSize": NumberInt(261120),
   "uploadDate": ISODate("2014-04-13T11:32:33.557Z"),
   "md5": "7b762939321e146569b07f72c62cca4f",
   "length": NumberInt(646)
}

以下是简单的 fs.chunks 集合文档:

{
   "files_id": ObjectId("534a75d19f54bfec8a2fe44b"),
   "n": NumberInt(0),
   "data": "Mongo Binary Data"
}
GridFsTemplate

gridFsTemplate类实现了GridFsOperations的接口,非常丰富,可以参照GridFsTemplate文档

官方文档

GridFS 上传文档示例

Mongodb 是一个开源的no-sql分布式数据库,Mongodb也为我们提供了基于文件的GFS分布式存储系统。因此利用Mongodb我们完全可以实现一个分布式的文件存储以及管理。

下面的内容主要为大家介绍,如何利用java,将大文件存入Mongodb数据库中。我们这里所说的大文件,是指大小在16M以上的文件,这也符合MongodbGFS的说明。mongodb是将文件进行分块,存储,当查询时,mongodb会帮你把你所需要的块进行组合然后展示给你,因此结合mongodb分布式的特性,我们可以轻易的构建一个分布式的文件存储。

在利用java驱动存储时,当我们获得需要存储的数据库连接之后,我们需要先创建一个bucket,官方的说明如下:

Create a GridFS Bucket

GridFS stores files in two collections: a chunks collection stores the file chunks, and a files collection stores file metadata. The two collections are in a common bucket and the collection names are prefixed with the bucket name.

mongodb是将文件分为两部分存储,一个是chunks,另一个是files。并且在 collection 的名字将会有你bucket的前缀。mongodb支持自定义的bucket的名字,当然也有默认,默认是files。

package com.aisino.uwcloud;

import com.mongodb.Block;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import com.mongodb.client.gridfs.GridFSUploadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.mongodb.client.gridfs.model.GridFSUploadOptions;
import org.bson.Document;
import org.bson.types.ObjectId;

import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by CP-CUI on 2020/12/25.
 */
public class MongodbGFS {

    private MongoClient mongoClient;

    // 我们进行操作的数据库
    private MongoDatabase useDatabase;

    // bucket
    private GridFSBucket gridFSBucket;

    public static void main(String[] args) {
        MongodbGFS mongodbGFS = new MongodbGFS();
        ObjectId objectId = mongodbGFS.saveFile("E:\\workFile\\平台建设_技术方案_合成New.doc");
        System.out.println(objectId);
    }

    // 初始化
    {
        ServerAddress serverAddress = new ServerAddress("localhost",27017);
        List<ServerAddress> addrs = new ArrayList<ServerAddress>();
        addrs.add(serverAddress);
        //MongoCredential.createScramSha1Credential()三个参数分别为 用户名 数据库名称 密码
        MongoCredential credential = MongoCredential.createScramSha1Credential("ueh", "ebip", "abc123ABC".toCharArray());
        List<MongoCredential> credentials = new ArrayList<MongoCredential>();
        credentials.add(credential);
        //通过连接认证获取MongoDB连接
        MongoClient mongoClient = new MongoClient(addrs,credentials);
        //连接到数据库
        useDatabase = mongoClient.getDatabase("ebip");
        // 自定义bucket name
        gridFSBucket = GridFSBuckets.create(useDatabase, "zt_files");
        // 使用默认的名字
        // gridFSBucket=GridFSBuckets.create(useDatabase);
    }

    // 将文件存储到mongodb,返回存储完成后的ObjectID
    public ObjectId saveFile(String url) {
        InputStream ins = null;
        ObjectId fileid = null;
        // 配置一些参数
        GridFSUploadOptions options = null;
        // 截取文件名
        String filename = url.substring((url.lastIndexOf("/") + 1), url.length());
        try {
            ins = new FileInputStream(new File(url));
            options = new GridFSUploadOptions().chunkSizeBytes(358400).metadata(new Document("type", "presentation"));

            // 存储文件,第一个参数是文件名称,第二个是输入流,第三个是参数设置
            fileid = gridFSBucket.uploadFromStream(filename, ins, options);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                ins.close();
            } catch (IOException e) {
            }
        }
        return fileid;
    }

    // 通过OpenUploadStream存储文件
    /**
     *
     * The GridFSUploadStream buffers data until it reaches the chunkSizeBytes and
     * then inserts the chunk into the chunks collection. When the
     * GridFSUploadStream is closed, the final chunk is written and the file
     * metadata is inserted into the files collection.
     *
     */
    public ObjectId saveFile2(String url) {
        ObjectId fileid = null;
        GridFSUploadStream gfsupload = null;
        // 配置一些参数
        GridFSUploadOptions options = null;
        // 截取文件名
        String filename = url.substring((url.lastIndexOf("/") + 1), url.length());
        try {
            options = new GridFSUploadOptions().chunkSizeBytes(358400).metadata(new Document("type", "presentation"));

            // 存储文件,第一个参数是文件名称,第二个是输入流,第三个是参数设置
            gfsupload = gridFSBucket.openUploadStream(filename, options);

            byte[] data = Files.readAllBytes(new File(url).toPath());

            gfsupload.write(data);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            gfsupload.close();
            fileid = gfsupload.getObjectId();
        }
        return fileid;
    }

    // 查询所有储存的文件
    public List<String> findAllFile() {
        List<String> filenames = new ArrayList<>();

        gridFSBucket.find().forEach(new Block<GridFSFile>() {

            @Override
            public void apply(GridFSFile t) {
                filenames.add(t.getFilename());
            }
        });

        return filenames;
    }

    // 删除文件
    public void deleteFile(ObjectId id) {
        gridFSBucket.delete(id);
    }

    // 重命名文件
    public void rename(ObjectId id, String name) {
        gridFSBucket.rename(id, name);
    }

    // 将数据库中的文件读出到磁盘上,参数,文件路径
    public String downFile(String url, ObjectId id) {
        FileOutputStream out = null;
        String result=null;
        try {
            out = new FileOutputStream(new File(url));
            gridFSBucket.downloadToStream(id, out);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                out.close();
                result=out.toString();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }


}

六、MongoDB数据迁移

Bin目录下没有mongoimport.exe mongoexeport.exe文件

需要单独下载

解压后目录,将这些文件copy到mongo安装路径下的bin下,即可做数据迁移和备份操作

报Access is denied异常解决,打开cmd时需要以管理员身份运行

执行mongoexport --uri=“mongodb://用户名:密码@远程服务器ip:27017/ebip” --collection=sys_file --out=c:\sys_file.json

或者

mongoexport -h 远程服务器ip --port 27017 -u 用户名 -p 密码 -d 数据库 -c 表名 -o c:\文件名.dat (速度比第一种方式慢)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YBz8bg1p-1609209485354)(file:///C:/Users/CP-CUI/AppData/Local/Temp/msohtmlclip1/01/clip_image024.jpg)]

导入本地

进入安装目录bin下 执行命令:

mongoimport -h 127.0.0.1 --port 27017 -u ueh -p abc123ABC -d ebip -c sys_file c:\sys_file.dat

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值