MongoDB
1)MongoDB介绍
对于社交类软件的功能,我们需要对它的交友/圈子功能特点做分析:
- 每天发布圈子的动态为海量数据
- 读多写少
- 数据价值较低,对事物性要求不高
- ……
针对以上特点,我们来分析一下:
-
mysql:关系型数据库,性能较差
-
redis:内存成本高
-
对于数据量大而言,显然不能够使用关系型数据库和内存数据库进行存储,我们需要通过MongoDB进行存储
探花交友项目:
- mysql数据库:存储用户信息等重要数据
- redis数据:提高热点数据的查询速度
- mongodb:承担社交的业务(圈子、小视频)功能
MongoDB简介
MongoDB 由C++语言编写,是一个跨平台的,面向文档
的数据库,是当前 NoSQL 数据库产品中最热门的一种。
它介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系(MySQL)数据库的产品。
它支持的数据结构非常松散,是类似JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。
官网地址:https://www.mongodb.com
MongoDB的特点
MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。
具体特点总结如下:
- 面向集合存储,易于存储对象类型的数据
- 模式自由
- 支持动态查询
- 支持完全索引,包含内部对象
- 支持复制和故障恢复
- 使用高效的二进制数据存储,包括大型对象(如视频等)
- 自动处理碎片,以支持云计算层次的扩展性
- 支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl及C++语言的驱动程 序, 社区中也提供了对Erlang及.NET 等平台的驱动程序
- 文件存储格式为 BSON(一种 JSON 的扩展)
MongoDB体系结构
MongoDB 的逻辑结构主要由:数据库(database)、 集合(collection)、文档(document)这三部分组成的。
- MongoDB 的文档(document),相当于关系数据库中的一行记录。
- 多个文档组成一个集合(collection),相当于关系数据库的表。
- 多个集合(collection),逻辑上组织在一起,就是数据库(database)。
- 一个 MongoDB 实例支持多个数据库(database)。 文档(document)、集合(collection)、数据库(database)的层次结构如下图:
为了更好的理解,下面与SQL中的概念进行对比:
RDBMS | MongoDB |
---|---|
database(数据库) | database(数据库) |
table (表) | collection( 集合) |
row( 行) | document( BSON 文档) |
column (列) | field (字段) |
index(唯一索引、主键索引) | index (支持地理位置索引、全文索引) |
join (主外键关联) | MongoDB不支持 |
primary key(指定某个列做主键) | primary key (不需要 指定 固定 _id 字段做为主键 自带的) |
MongoDB数据类型
数据类型 | 说明 | 解释说明 | Document举例 |
---|---|---|---|
String | 字符串 | UTF-8 编码的字符串才是 合法的。 | {key:“cba”} |
Integer | 整型数值 | 根据你所采用的服务器, 可分为 32 位或 64 位。 | {key:1} |
Boolean | 布尔值 | 用于存储布尔值(真/ 假)。 | {key:true} |
Double | 双精度浮点值 | 用于存储浮点值 | {key:3.14} |
ObjectId | 对象ID | 用于创建文档的ID | {_id:new ObjectId()} |
Array | 数组 | 用于将数组或列表或多个 值存储为一个键 | {arr:[“a”,“b”]} |
Timestamp | 时间戳 | 从开始纪元开始的毫秒数 | { ts: new Timestamp() } |
Object | 内嵌文档 | 文档可以作为文档中某个 key的value | {o:{foo:“bar”}} |
Null | 空值 | 表示空值或者未定义的对 象 | {key:null} |
Date或者 ISODate | 格林尼治时间 | 日期时间,用Unix日期格 式来存储当前日期或时 间。 | {birth:new Date()} |
File | 文件 | 1、二进制转码(Base64)后 存储 (<16M) 2、 GridFS(>16M) | GridFS 用两个集合来存储一个文件:fs.files与 fs.chunks 真正存储需要使用mongofiles -d gridfs put song.mp |
对于一些访问量高的,数据价值低业务场景,推荐使用MongoDB
2)MongoDB命令 【理解】
MongoDB的基本操作
# 查看数据库
show dbs
# 切换数据库 如果没有对应的数据库则创建
use 数据库名
# 创建集合
db.createCollection("集合名")
# 查看集合
show tables或者show collections
# 删除集合
db.集合名.drop()
# 删除当前数据库
db.dropDatabase()
新增数据
语法:
db.collection.insert({json数据})
练习:
use testdb
db.createCollection("user")
db.user.insert({username:'zhangsan',age:'18',address:'北京顺义'})
更新数据
语法:
db.collection.update(
<query>, # 指定条件 where 条件
<update>, # 指定修改那个字段 update set xxx
[ #以下参数可选
upsert: <boolean>,
multi: <boolean>
]
)
参数说明:
-
query : update的查询条件,类似sql update查询内where后面的。
-
update : update的对象和一些更新的操作符如:$set,也可以理解为sql update查询内set后面的
例如:update from 表 set<> xx=? where() xx=?
-
upsert : (可选)这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
-
multi : (可选)mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
练习:根据用户名做更新
//修改格式 参数1:条件 参数2:要修改的内容 参数3:条件不成立是否新增 参数4:是否做批量
db.user.update({query},{update},{可选},{可选})
//1 修改姓名叫jack2的年龄为10
//错误的写法 此写法会用age替换所有字段
db.user.update({username:'jack2'},{age:10})
//正确的写法:$set
db.user.update({username:'jack22'},{$set:{age:10}})
//2 修改姓名叫jack66的年龄为10 默认没该条件 就不操作了 但是如果加了true 代表没找到就新增
db.user.update({username:'jack66'},{$set:{age:10}},true)
//3 根据多个相同的条件做修改
db.user.update({age:'18'},{$set:{username:'jack8888'}},false,true)
#更新数据
db.user.update({username:'zhangsan'},{$set:{age:22}})
#错误示范:如果这样写,会删除掉其他的字段
db.user.update({username:'zhangsan'},{age:25})
#更新一个不存在的字段时,会新增
db.user.update({username:'lisi'},{$set:{sex:1}}) #更新数据
#更新不存在的用户时,默认不会新增数据
db.user.update({username:'wangwu'},{$set:{sex:1}})
#如果设置upsert参数为true,就是新增数据
db.user.update({username:'wangwu'},{$set:{sex:1}},true)
删除数据
练习
#插入4条测试数据
db.user.insert({username:'jack',age:18,address:'北京顺义'})
db.user.insert({username:'jack',age:22,address:'北京顺义'})
db.user.insert({username:'jack',age:22,address:'北京顺义'})
db.user.insert({username:'jack',age:24,address:'北京顺义'})
db.user.insert({username:'jack6666',age:24,address:'北京顺义'})
#删除所有数据
db.user.remove({})
#说明:为了简化操作,官方推荐使用deleteOne()与deleteMany()进行删除数据操作。
db.user.deleteOne({username:'jack'}) #删除单个数据
db.user.deleteMany({username:'jack'}) #删除多个数据
查询数据
语法:
db.集合.find(
[query],
[fields]
)
参数说明:
- query :可选,使用查询操作符指定查询条件
- fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
条件查询:
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key>:<value>} | db.col.find({"likes":"黑马程序员"}) | where likes = '黑马程序员' |
小于 | {<key>:{$lt:<value>}} | db.col.find({"likes":{$lt:50}}) | where likes < 50 |
小于或等于 | {<key>:{$lte:<value>}} | db.col.find({"likes":{$lte:50}}) | where likes <= 50 |
大于 | {<key>:{$gt:<value>}} | db.col.find({"likes":{$gt:50}}) | where likes > 50 |
大于或等于 | {<key>:{$gte:<value>}} | db.col.find({"likes":{$gte:50}}) | where likes >= 50 |
不等于 | {<key>:{$ne:<value>}} | db.col.find({"likes":{$ne:50}}) | where likes != 50 |
练习:
#插入4条测试数据
db.user.insert({username:'zhangsan',age:18,address:'北京顺义'})
db.user.insert({username:'lisi',age:22,address:'北京顺义'})
db.user.insert({username:'wangwu',age:22,address:'北京顺义'})
db.user.insert({username:'zhaoliu',age:24,address:'北京顺义'})
#查询全部数据
db.user.find()
#查询username为zhangsan的数据
db.user.find({username:'zhangsan'})
#and查询,age等于22并且username等于wangwu的数据
db.user.find({age:22,username:'wangwu'})
#查询小于等于21的数据
db.user.find({age:{$lte:21}})
#只查询username字段和age字段
db.user.find({},{username:true,age:true})
#分页查询:Skip()起始索引,limit()每页显示一个数
db.user.find().count() #查询数据条数
db.user.find().skip(start).limit(查询的条数) #start起始数据
db.user.find().sort({age:-1}) #按照age倒序排序,-1为倒序 desc,1为正序 asc
创建索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
#插入数据
db.user.insert({username:'zhangsan',age:18,address:'北京顺义'})
#创建索引
db.user.createIndex({'age':1})
#查看索引
db.user.getIndexes()
3)基本Java操作MongoDB【了解】
环境搭建
创建:
mongodb-demo
,并导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>3.9.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
入门Demo(简单了解)
import com.mongodb.client.*;
import org.bson.Document;
import java.util.function.Consumer;
public class DemoTest {
public static void main(String[] args) {
// 建立连接
MongoClient mongoClient =
MongoClients.create("mongodb://192.168.136.160:27017");
// 选择数据库
MongoDatabase mongoDatabase = mongoClient.getDatabase("testdb");
// 选择表
MongoCollection<Document> userCollection = mongoDatabase.getCollection("user");
// 查询前10条
FindIterable<Document> documents = userCollection.find().skip(0).limit(10);
for (Document document : documents) {
System.out.println(document.toJson());
}
// 关闭连接
mongoClient.close();
}
}
4)SpringBoot整合MongoDB(重点)
spring-data对MongoDB做了支持,使用spring-data-mongodb可以简化MongoDB的操作,封装了底层的mongodb
地址:https://spring.io/projects/spring-data-mongodb
使用Spring-Data-MongoDB很简单,只需要如下几步即可:
- 导入起步依赖
- 编写配置信息
- 编写实体类
- 注入MongoTemplate对象,完成CRUD操作
4.1、环境搭建
第一步,导入依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 设置编译版本为1.8 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
第二步,编写application.yml配置文件
spring:
data:
mongodb:
uri: mongodb://192.168.136.160:27017/testdb
第三步,编写启动类
package com.tanhua.mongo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MongoApplication {
public static void main(String[] args) {
SpringApplication.run(MongoApplication.class, args);
}
}
4.2、完成基本操作
第一步,编写实体类
package cn.itcast.mongodb.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("user")
public class Person {
@Id
private ObjectId id;
@Indexed
private String username;
@Indexed
private Integer age;
private String address;
}
第二步,通过MongoTemplate完成CRUD操作
package cn.itcast.mongodb;
import cn.itcast.mongodb.domain.Person;
import org.bson.types.ObjectId;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoTest {
@Autowired
private MongoTemplate mongoTemplate;
@Test //新增
public void testSave(){
Person person = new Person(new ObjectId(),"zhangsan",20,"北京顺义");
mongoTemplate.insert(person);
// mongoTemplate.insert(person,"user_100"); //还可以继续指定要保存的集合名称
}
@Test
public void testDelete(){
// 删除username是wangwu
Query query = new Query(new Criteria("username").is("wangwu"));
// mongoTemplate.remove(query,"user");
mongoTemplate.remove(query,Person.class);
}
@Test
public void testUpdate(){
// 把username是zhangsan的年龄改成30
// update user set age=30 where username='zhangsan'
Query query = new Query( Criteria.where("username").is("zhangsan"));
Update update = new Update();
update.set("age",30);
// Query var1, Update var2, Class<?> var3
mongoTemplate.upsert(query,update,Person.class);
}
@Test
public void testFindById(){
// ObjectId("5ff676fcdcb81d5544712f36")
Person person = mongoTemplate.findById(new ObjectId("5ff676fcdcb81d5544712f36"),Person.class);
System.out.println(person);
}
@Test
public void testFindByUsername(){
Query query = new Query( Criteria.where("username").is("zhangsan"));
List<Person> personList = mongoTemplate.find(query, Person.class);
System.out.println(personList);
}
@Test
public void testFindByPage(){
Query query = new Query();
// query.with(new Sort(Sort.Direction.DESC,"age")); //根据age降序
query.with(new Sort(Sort.Direction.ASC,"age")); //根据age降序
query.skip(1).limit(1); //skip:起始位置 limit:每页显示的条数
List<Person> personList = mongoTemplate.find(query, Person.class);
System.out.println(personList);
}
}