Mongodb专题之快速入门

MongoDB搭建方法见:Mongodb 教程之搭建

1. 什么是NoSQL

NoSQL(Not Only SQL)”不仅仅是SQL”

随着互联网Web2.0网站的兴起,传统的关系型数据库在处理Web2.0网站,特别是超大规模和高并发的SNS类型的Web.20纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关型的数据库则哟与其本身的特点得到了非常迅速的发展。
NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战。

NoSQL是一种不同于关系数据库的数据库管理系统设计方式,是对非关系数据库的统称.它所采用的是数据模型并非传统关系数据库的关系模型,而是类似键值、列族、文档等非关系模型.

1.1 关系型数据库遵循ACID原则

事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:

  1. A (Atomicity) 原子性

    原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

    比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

  1. C (Consistency) 一致性

    一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

    例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。

  2. I (Isolation) 独立性

    所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。

    比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。

  3. D (Durability) 持久性

    持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

1.2 RDBMS vs NoSQL

RDBMS

  • 高度组织化结构化数据
  • 结构化查询语言(SQL) (SQL)
  • 数据和关系都存储在单独的表中。
  • 数据操纵语言,数据定义语言
  • 严格的一致性
  • 基础事务

NoSQL

  • 代表着不仅仅是SQL
  • 没有声明性查询语言
  • 没有预定义的模式
    -键 - 值对存储,列存储,文档存储,图形数据库
  • 最终一致性,而非ACID属性
  • 非结构化和不可预知的数据
  • CAP定理
  • 高性能,高可用性和可伸缩性

1.3 NoSQL的优缺点

  1. 优点:

    • 高可扩展性

    • 分布式计算

    • 低成本

    • 架构的灵活性,半结构化数据

    • 没有复杂的关系

  2. 缺点:

    • 没有标准化

    • 有限的查询功能

    • 最终一致是最不直观的程序

1.4 CAP定理(CAP theorem)

在计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer`s theorem),它指出对于一个分布式计算机系统来说,不可能同时满足以下三点:

  • 一致性Consistency:所有节点在同一时间具有相同的数据
  • 可用性Availability: 保证每个每个请求不管成功或者失败都有响应
  • 分区容错性Partition tolerance:系统中任意信息的丢失或失败不会影响系统的继续运行

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。

  • CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。

  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

1.5 BASE

BASE: Basically Available, Soft-state, Eventually Consistent,由Eric Brewer定义

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性、可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

BASE是NoSQL数据库通常对可用性及一致性的弱要求原则:

  • Basically Available –基本可用

  • Soft-state –软状态/柔性事务。 “Soft state” 可以理解为”无连接”的, 而 “Hard state” 是”面向连接”的

  • Eventually Consistency – 最终一致性, 也是 ACID 的最终目的。

1.6 BASE vs ACID

ACID BASE
原子性Atomicity 基本可用Basically Available
一致性Consistency 软状态 / 柔性事务 Soft state
隔离性 Isolation 最终一致性Eventual Consistency
持久性 Durable -

1.7 NoSQL数据库分类

类型 部分代表 特点
列存储 Hbase、Cassandra、Hypertable 顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势
文档存储 MongoDB、CouchDB 文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能
Key-value存储 Tokyo Cabinet/Tyrant、Berkeley DB、Redis、MemcacheDB 可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)
图存储 Neo4j、FlockDB 图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便
对象存储 db4o、Versant 通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据
XML数据库 BaseX、Berkeley DB XML 高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath

2. MongoDB特点

  1. 文档导向: MongoDB存储BSON(二进制JSON)文档,这些文档可以包含复杂的数据结构,如数组和嵌套对象

  2. 高性能:MongoDB提供了高性能的数据持久话和查询能力,特别是对于写入密集型的应用

  3. 水平扩展:通过分片Sharding技术,Mongodb可以在多个服务器之间分布数据,实现水平扩展

  4. 高可用性:MongoDB支持副本集(replica sets),提供数据的自动故障转移和数据冗余

  5. 灵活的聚合框架: MongoDB提供了一个强大的聚合框架,允许执行复杂的数据处理和聚合操作

  6. 丰富的查询语句:MongoDB的查询语句MQL支持丰富的查询操作,包括文本搜索、地理位置查询等

  7. 存储过程:MongoDB支持在数据库内部执行Javascript代码,允许定义和执行复杂的数据处理逻辑

  8. GridFS: 队医存储大于BSON文档大小限制(16MB)的文件,MongoDB提供了GridFS,一种用于存储和检索大文件的规范

  9. 安全性: MongoDB提供了多层次的安全特性,包括认证、授权和加密

  10. 驱动程序和工具:MongoDB拥有广泛的驱动程序支持,适用于不同的编程语言,以及各种管理工具和可视化界面

  11. 社区和生态系统:MongoDB拥有一个活跃的开发者社区,提供了大量的教程、文档和第三方工具

3. 案例工程

  1. 添加pom依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ygb</groupId>
    <artifactId>mongodb</artifactId>
    <version>1.0</version>
    <name>mongodb</name>
    <url>http://www.example.com</url>
    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>8</maven.compiler.release>
    </properties>
    <parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.6.6</version>
    </parent>

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
    <version>4.13.2</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-test</artifactId>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.14.2</version>
    </dependency>
    </dependencies>
    </project>
  2. 创建Entity

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.ygb;

    import lombok.Data;
    import lombok.ToString;
    import lombok.experimental.Accessors;

    @Data
    @ToString
    @Accessors(chain = true)
    public class Status {
    private Integer weight;
    private Integer heigth;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package com.ygb;

    import lombok.Data;
    import lombok.ToString;
    import lombok.experimental.Accessors;
    import org.springframework.data.mongodb.core.mapping.MongoId;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import java.util.Date;

    @Data
    @ToString
    @Accessors(chain = true)
    public class User {
    /**
    * 使用@MongoId 能更清洗的指定 _id 主键
    */
    @MongoId
    private String id;
    private String name;
    private String sex;
    private Integer salary;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date birthday;
    private String remake;
    private Status status;
    }
  3. 启动类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.ygb;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication
    public class DemoApplication {
    public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
    }
    }
  4. application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    server:
    port: 8080

    spring:
    data:
    mongodb:
    #不需要用户名和密码 mongodb://ip:port/admin
    uri: mongodb://192.168.44.144:27017/admin
    #需要用户名和密码
    #mongodb://username:password@ip:port/admin
  5. 测试方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = DemoApplication.class)
    public class DemoApplicationTest {
    private Logger log = LoggerFactory.getLogger(getClass());
    private static final String COLLECTION_NAME = "users";

    @Resource
    private MongoTemplate mongoTemplate;

    @Test
    public void createIndex() {
    String field = "name";
    mongoTemplate.getCollection(COLLECTION_NAME).createIndex(Indexes.ascending(field));
    }
    @Test
    public void insert() {
    User user = new User()
    .setId("10")
    .setAge(22)
    .setSex("man")
    .setRemake("nothing")
    .setSalary(100)
    .setName("xiaoyuge")
    .setBirthday(new Date())
    .setStatus(new Status().setHeigth(180).setWeight(140));
    final User insert = mongoTemplate.insert(user, COLLECTION_NAME);
    log.info("user info: {}", insert);
    }
    }