概念:
MongoDB 是一个文档数据库(以 JSON 为数据模子),由 C++ 语言编写,旨在为 WEB 应用提供可扩展的高性能数据存储办理方案。 MongoDB 是一个介于关系数据库和非关系数据库之间的产品,黑白关系数据库当中功能最丰富,最像关系数据库的。它支持的数据布局非常疏松,数据格式是BSON ,一种类似 JSON 的二进制形式的存储格式,简称Binary JSON ,和 JSON 一样支持内嵌的文档对象和数组对象,因此可以存储比较复杂的数据类型。MongoDB 最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部门功能,而且还支持对数据建立索引。原则上 Oracle 和 MySQL 能做的变乱, MongoDB 都能做(包括 ACID 事务)。 sql 与MongoDB 比较:
数据库( database ):最外层的概念,可以理解为逻辑上的名称空间,一个数据库包罗多个不同名 称的集合。 集合( collection ):相当于 SQL 中的表,一个集合可以存放多个不同的文档。 文档( document ):一个文档相当于数据表中的一行,由多个不同的字段组成。 字段( field ):文档中的一个属性,等同于列( column )。 索引( index ):独立的检索式数据布局,与 SQL 概念同等。 id :每个文档中都拥有一个唯一的 id 字段,相当于 SQL 中的主键( primary key )。 视图( view ):可以看作一种虚拟的(非真实存在的)集合,与 SQL 中的视图类似。从 MongoDB 3.4 版本开始提供了视图功能,其通过聚合管道技能实现。 聚合操作( $lookup ): MongoDB 用于实现 “ 类似 ” 表毗连( tablejoin )的聚合操作符。
MongoDB特点:
半布局化,在一个集合中,文档所拥有的字段并不必要是雷同的,而且也不必要对所用的字段进行 声明。 弱关系, MongoDB没有外键的约束,也没有非常强大的表毗连本领。 优势:
MongoDB 基于灵活的 JSON 文档模子,非常适合灵敏式的快速开辟。与此同时,其与生俱来的高可用、 高水平扩展本领使得它在处理海量、高并发的数据应用时颇具优势。 图文联合解释特点:
从错综复杂的关系模子到一目了然的对象模子(简单直观) 最简单快速的开辟方式(快速)
快速响应业务变化(灵活)
原生的高可用(优势)
横向扩展本领(优势)
MongoDB应用场景:
游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、 积分 等直接以内嵌文档的形式存储, 方便查询、更新; 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不停更新,以 MongoDB 内嵌 数组的形式来存储,一次查询就能将订单全部的变更读取出来; 交际场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实 现附近的人、地点等功能; 物联网场景,使用 MongoDB 存储全部接入的智能装备信息,以及装备报告的日志信息,并对这些 信息进行多维度的分析; 视频直播,使用 MongoDB 存储用户信息、礼物信息等; 大数据应用,使用云数据库 MongoDB 作为大数据的云存储体系,随时进行数据提取分析,掌握行 业动态。 如何考虑是否选择MongoDB?
只要有一项需求满足就可以考虑使用 MongoDB ,匹配越多,选择 MongoDB 越合适。
虚拟机使用
MongoDB下载
https://www.mongodb.com/try/download/community
下载压缩包
进行解压安装等操作
设置
- systemLog:
- destination: file
- path: "/usr/local/mongodb/log/mongod.log"
- # log path
- logAppend: true
- storage:
- dbPath: "/usr/local/mongodb/data/db"
- #存储引擎
- journal:
- #是否启用journal日志
- enabled: true
- net:
- bindIp: 0.0.0.0
- port: 27017
- # port
- processManagement:
- fork: true
复制代码 启动
- ./bin/mongo
- d -f ./mongod.conf
复制代码 成功
查看日志是否使用
查看进程mongodb是否启动
创建启动文件
关闭mongodb
毗连mongodb
use admin
关闭成功并退出
查看进程
MongoDB使用
本地window毗连
黑窗口中在mongodb安装目录的bin目录下输入mongo
如果更改了端标语
远程毗连
- mongo --host=127.0.0.1 --port=27017
复制代码
如果连不上就关闭防火墙试试
查抄防火墙
关闭防火墙
- systemctl stop firewalld.service
复制代码 克制启用
- systemctl disable firewalld.service
复制代码
启动
云服务毗连成功
我这用的虚拟机的也可已毗连
接着操作虚拟机的MongoDB
先登录进入mongo
指令查看数据库
常用命令
- show dbs | show databases 显示数据库列表
- use 数据库名 切换数据库,如果不存在创建数据库
- db.dropDatabase() 删除数据库
- show collections | show tables 显示当前数据库的集合列表
- db.集合名.stats() 查看集合详情
- db.集合名.drop() 删除集合
- show users 显示当前数据库的用户列表
- show roles 显示当前数据库的角色列表
- show profile 显示最近发生的操作
- load("xxx.js") 执行一个JavaScript脚本文件
- exit | quit() 退出当前shell
- help 查看mongodb支持哪些命令
- db.help() 查询当前数据库支持的方法
- db.集合名.help() 显示集合的帮助信息
- db.version() 查看数据库版本
复制代码
db 查看当前数据库
db.dropDatabase() 删除当前数据库
db.createCollection("") 创建表
show tables 查看当前数据库中表
大概show collections
当库中有数据时就可以显示了
命令操作
插入数据
单条数据插入
插入方法使用 insert() 大概 save() 大概 insertOne() 方法
- db.集合名.insert(BSON格式文档内容)
- 或者
- db.集合名.save(BSON格式文档内容)
- 或者
- db.集合名.insertOne(BSON格式文档内容)
复制代码
- save():如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne() 或 db.collection.replaceOne() 来代替。
- insert(): 若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不生存当前数据。
- db.student.insert({name:"张三",age:15})
复制代码 默认情况下,MongoDB使用 _id 字段作为主键,自动生成。如果手动指定,则使用手动指定的数据。
_id 字段类型是ObjectId,手动指定id时可以使用ObjectId,也可以使用MongoDB支持的恣意类型
批量插入
- db.集合名.insertMany(
- [文档1, 文档2...],
- {
- ordered: 指定MongoDB是否有序插入。可选值
- }
- )
复制代码 MongoDB的批量插入并不是同时成功大概同时失败。如果在插入过程中有一条数据失败,就会停止插入,但是在此之前的数据都会插入成功。
自界说插入id值
同id进行修改(存在修改不存在插入)(不保举使用)
批量插入
- db.student.insertMany
- (
- [
- { "_id" : ObjectId("65a2db55dc4aa5e80ea4f1c0"), "name" : "张三", "age" : 15, "sex" : "男" },
- { "_id" : ObjectId("65a2dc37dc4aa5e80ea4f1c1"), "name" : "李四" },
- { "_id" : ObjectId("65a2dc64dc4aa5e80ea4f1c2"), "name" : "王二", "age" : 14 },
- { "_id" : 1, "name" : "李四" }
- ],
- {
- ordered: true
- }
- )
复制代码
支持try catch
插入数据较多的情况下大概会报错,可以在命令前后使用try catch进行异常捕获
- try {
- db.集合名.insertMany()
- } catch(e) {
- print(e)
- }
复制代码- try{db.student.insertMany
- (
- [
- { "_id" : ObjectId("65a2db55dc4aa5e80ea4f1c0"), "name" : "张三", "age" : 15, "sex" : "男" },
- { "_id" : ObjectId("65a2dc37dc4aa5e80ea4f1c1"), "name" : "李四" },
- { "_id" : ObjectId("65a2dc64dc4aa5e80ea4f1c2"), "name" : "王二", "age" : 14 },
- { "_id" : 1, "name" : "李四" }
- ],
- {
- ordered: true
- }
- )}catch(e){print(e)}
复制代码 创建集合语法
- db.createCollection(name, options)
复制代码
更新文档
更新文档使用update方法
- db.集合名.update(
- {BSON格式查询条件},
- {BSON格式要更新的内容},
- {
- upsert: 布尔类型,指定如果不存在update的记录,是否插入。默认false
- multi: 默认false,只更新找到的第一条记录。如果为true,则更新查询条件下的所有记录
- }
- )
复制代码 覆盖修改
将符合条件 "_id":"1"的第一个文档替换为{"name":"dd","age":10}。
- db.student.update({_id:1},{"name":"dd","age":10})
复制代码 局部修改 批量修改
使用 $set 修改器指定要更新的 key , key 不存在则创建,存在则更新 将符合条件 "name":" dd " 的全部文档更新 name 和 age 的值。 - db.student.update({"name":"dd"},{$set:{"name":"ss","age":10}},{multi:true})
复制代码 multi : false 表现更新第一个匹配的文档, true 表现更新全部匹配的文档。 如果不加multi参数,只会更新符合条件的一条数据 列值自增 如果想要 对某列的值进行自增操作,可以使用 $inc - db.集合名.update(
- {_id: "1"},
- {$inc: {age: NumberInt(1)}}
- )
复制代码 删除文档
1 、删除全部文档
2、删除符合条件的文档
- db.student.remove({"name":"dd"})
复制代码 查询文档
- db.collection.find(query, projection)
复制代码 query :查询条件,可不填 projection :投影查询 key ,可不填 查询使用 find() 大概 findOne() 方法进行 1 、 查询全部 2 、查询符合条件的记录 查询 name 等为 " dd " 的文档。 - db.student.find({"name":"dd"})
复制代码 3 、投影查询 只显示 name 和 age 两个 key , _id 主键不显示。 默认情况下,查询的效果是返回全部字段。如许的话性能大概会比较低。一样平常我们只查询必要的部门字段,就可以使用投影查询
如,只查询name, age字段
- db.student.find({"name":"dd"},{name:1,age:1,_id:0})
复制代码 条件毗连查询
AND 条件
find() 方法可以传入多个键值对,类似于SQL的AND条件
如,查询性别是男,年岁在18岁的用户
- db.stdent.find({sex: "1", age: "18"})
复制代码 OR 条件
MongoDB提供了关键字 $or 用来实现or查询
- db.集合名.find({$or: [{key1, value1}, {key2, value2}]})
复制代码
AND 和 OR 联合使用
- db.student.find({sex: 1, $or: [{age: 27}, {age: 29}]})
复制代码
统计查询
统计全部性别为男的数据
- db.student.count({sex: 1})
复制代码
分页查询
使用 limit 读取指定数量的数据, skip 跳过指定数量的数据,二者搭配来进行分页查询。使用逻辑和MySql中的limit一样。
查询返回前三条记录,limit参数默认是20
跳过前3条记录,skip参数默认是0
每页查询2条数据
- db.集合.find().skip(0).limit(2)
- db.集合.find().skip(2).limit(2)
- db.集合.find().skip(3).limit(2)
复制代码
排序查询
排序查询使用 sort 方法。sort方法可以指定排序的字段,值为1升序,值为-1降序
根据性别升序排序,并根据年岁降序排序
- db.student.find().sort({sex: 1, age: -1})
复制代码
再进行分页,每页5条
- db.student.find().sort({sex: 1, age: -1}).skip(0).limit(5)
复制代码
脚色权限操作
查询全部脚色权限(仅用户自界说脚色)
- db.runCommand({rolesInfo: 1})
复制代码 查询全部脚色权限(包罗内置脚色)
- db.runCommand({rolesInfo: 1, showBuiltinRoles: true})
复制代码 查询当前数据库中指定脚色的权限
- db.runCommand({rolesInfo: 角色名})
复制代码 查询其他数据库中指定的脚色权限
- db.runCommand({rolesInfo: {role: 角色名, db: 数据库名}})
复制代码 查询多个脚色权限
- db.runCommand({rolesInfo: [角色名...., {role: 角色名, db: 数据库名}]})
复制代码 常见脚色
安全认证
关闭数据库
- mongo --port 27017
- use admin
- db.shutdownServer()
复制代码 添加用户和权限
- ./usr/local/mongodb/bin/mongod -f ./usr/local/mongod.conf
复制代码 登录数据库
- ./usr/local/mongodb/bin/mongo
复制代码 根据实际路径合理操作
创建体系超级管理员mongoroot和admin数据库的管理用户mongoadmin
- # 切到admin
- use admin
- # 创建系统超级用户mongoroot,密码123456,角色root
- db.createUser({user: "mongoroot", pwd: "123456", roles: ["root"]})
- # 创建admin库的管理员
- db.createUser({user: "mongoadmin",pwd: "123456", "roles": [{role: "userAdminAnyDatabase", db:"admin"}]})
- # 查看已经创建的用户
- db.system.users.find()
复制代码
MongoDB默认把用户信息存放到 admin 数据库的 system.users 表中
创建用户如果不指定数据库,则创建的用户在全部数据库上有效
认证测试
先关闭数据库
- use admin
- db.shutdownServer()
复制代码 重新启动mongodb,开启认证
参数方式
- ./usr/local/mongodb/bin/mongod -f ./mongodb/mongod.conf --auth
复制代码 根据目录合理操作
我这目录位置
- ./bin/mongo
- d -f ./mongod.conf --auth
复制代码
设置文件方式
编辑设置文件
- security:
- #开启授权认证
- authorization: enabled
复制代码 正常启动
- ./usr/local/mongodb/bin/mongod -f ./mongodb/mongod.conf
复制代码 我这里
- ./bin/mongo
- d -f ./mongod.conf
复制代码 毗连时认证
- /usr/local/mongodb/bin/mongo --host 127.0.0.1 --authenticationDatabase=admin --port 27017 -u mongoroot -p 123456
复制代码 -u 用户名
-p 密码
-- authenticationDatabase:指定要登录的数据库
我用的
- ./bin/mongo
- --host 192.168.80.100 --authenticationDatabase=admin --port 27017 -u mongoroot -p 123456
复制代码
暴力关闭数据库补救
暴力关闭数据库
- ps -aux|grep monogodb
- kill -9 进程号
复制代码 暴力关闭后,大概会存在数据的损坏,导致mongodb无法启动,可以通过下面的操作规复
删除lock文件
- rm -f /mongodb/data/db/*.lock
复制代码 修复数据
- /usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/data/db
复制代码 索引
索引通常可以大概极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文档并选取那些符合查询条件的记录。
这种扫描全集合的查询效率黑白常低的,特殊在处理大量的数据时,查询可以要花费几十秒乃至几分钟,这对网站的性能黑白常致命的。
索引是特殊的数据布局,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种布局
MongoDB中使用 B树 数据布局存储索引,B树在本次课程中不作讲解。
索引分类
单字段索引
MongoDB支持在文档单个字段上创建用户界说的升序/降序索引,称之为 单字段索引
复合索引
MongoDB还支持多个字段的索引,称之为 复合索引
复合索引中对字段顺序也有要求,如果复合索引是由 {age: 1, sex: -1} 组成,就会先按照age正序排序,再按照sex倒序排序
地理空间索引
为了支持对地理坐标的有效查询,MongoDB提供了二维索引和二维球面索引
文本索引
MongoDB提供了文本索引,支持在集合中搜刮字符串内容。
哈希索引
为了支持散列的分片,MongoDB提供了散列索引,它对字段值的散列进行索引。哈希索引只支持 = 条件查询,不支持范围查询。
索引操作
创建索引
单字段索引:对 age 字段建立索引
- db.student.createIndex({age: 1})
复制代码 复合索引:对 age 和 sex 同时创建复合索引
- db.student.createIndex({age: 1, sex: -1})
复制代码
查看索引
返回一个集合中全部的索引
此中,_id 是默认的索引。
MongoDB在创建集合的过程中,在_id字段上创建一个唯一的索引,名称为 _id_ ,该索引可以防止客户端插入两个具有雷同值的文档,该索引不可以被删除。
查看看集合索引大小
删除索引
删除指定索引
- db.集合名.dropIndex(索引名称或索引键值对)
复制代码 如删除age上的升序索引
- db.student.dropIndex({age: 1})
- 或者
- db.student.dropIndex("age_1")
复制代码 删除全部索引
该方法并不会将_id索引删除,只能删除_id之外的索引
查询分析
MongoDB 查询分析可以确保我们所建立的索引是否有效。
查询分析常用的方法是 explain()
explain 操作提供了查询信息、使用索引、查询统计等,有利于我们对索引的优化。
先在user中创建age和sex索引
- db.student.createIndex({age: 1, sex: 1})
复制代码
再使用explain对查询进行分析
- db.student.find({age: 18, sex: 1, _id: 1}).explain()
复制代码
stage:当值为 COLLSCAN 时,表现全集合扫描,如许的性能是比较低的。当值为 IXSCAN 时,是基于索引扫描,创建索引后我们必要包管查询是基于索引扫描的
indexOnly:为true时表现使用到了索引
覆盖索引查询
覆盖索引查询和MySQL中的类似。当查询条件和所要查询的列全部都在索引中时,MongoDB会直接从索引返回效果。如许的查询性能非常的高
SpringDataMongoDB
项目搭建
创建数据库 及毗连账号
- ./bin/mongo
- use mydbsuse admindb.auth("mongoroot","123456")use mydbsdb.createUser({user: "cqhshr",pwd: "123456",roles: [{role: "readWrite",db: "mydbs"}]})
复制代码 如果出现这种错误
试试验证登录
- mongo --host 127.0.0.1 --authenticationDatabase=admin --port 27017 -u root -p root
复制代码
(1)创建项目 bbs,pom.xml引入依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-mongodb</artifactId>
- </dependency>
复制代码
(2)application.yml中加入以下设置
- spring:
- #数据源配置
- data:
- mongodb:
- #主机地址
- host: 127.0.0.1
- #数据库
- database: student
- #默认端口是27017
- port: 27017
复制代码 SpringDataMongoDB毗连认证
当数据库设置了安全认证后,想要使用SpringDataMongoDB毗连MongoDB,就必要使用 username:password@hostname/dbname 格式 ,username为用户名,password为密码
- spring:
- #数据源配置
- data:
- mongodb:
- # 认证时配置
- uri: mongodb://username:password@127.0.0.1:27017/student?authSource=admin&authMechanism=SCRAM-SHA-1
复制代码 编写接口与实体类

- package com.cqh.entity;
- import org.springframework.data.annotation.Id;
- import org.springframework.data.mongodb.core.index.CompoundIndex;
- import org.springframework.data.mongodb.core.mapping.Document;
- import org.springframework.data.mongodb.core.mapping.Field;
- import org.springframework.stereotype.Component;
- import java.io.Serializable;
- import java.util.Date;
- /**
- * @author cqh
- * @date 2024/1/14
- * @Description
- */
- @Document("user") //指定集合
- @CompoundIndex(def = "{'age': -1}") //指定索引
- public class User implements Serializable {
- @Id
- private String id;
- @Field("name")
- private String name;
- // @Field 当名称与数据库一样时可以省略
- private Integer age;
- private String address;
- private Date createTime;
- private Integer state;
- private Integer followNum;
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public Date getCreateTime() {
- return createTime;
- }
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
- public Integer getState() {
- return state;
- }
- public void setState(Integer state) {
- this.state = state;
- }
- public Integer getFollowNum() {
- return followNum;
- }
- public void setFollowNum(Integer followNum) {
- this.followNum = followNum;
- }
- public User() {
- }
- }
复制代码
- 实体类必要使用 @Document 注解标识为MongoDB文档,并指定集合名。
- @Id 注解指定文档的主键,不建议省略
- @CompoundIndex 注解指定复合索引,可以在Java类中添加索引,也可以在MongoDB中添加
- @Indexed 注解指定单字段索引。
- package com.cqh.dao;
- import com.cqh.entity.User;
- import org.springframework.data.mongodb.repository.MongoRepository;
- import org.springframework.stereotype.Repository;
- /**
- * @author cqh
- * @date 2024/1/14
- * @Description
- */
- @Repository
- public interface UserRepository extends MongoRepository<User,String> {
- }
复制代码 (3)启动项目,看控制台是否报错

编写测试类测试方法

- package com.cqh;
- import com.cqh.dao.UserRepository;
- import com.cqh.entity.User;
- 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.test.context.junit4.SpringJUnit4ClassRunner;
- import java.util.Date;
- /**
- * @author cqh
- * @date 2024/1/14
- * @Description
- */
- @RunWith(SpringJUnit4ClassRunner.class)
- @SpringBootTest
- public class MongoDBTest {
- @Autowired
- private UserRepository userRepository;
- @Test
- public void testSave(){
- User user = new User();
- user.setName("张三");
- user.setAge(18);
- user.setAddress("重庆");
- user.setCreateTime(new Date());
- user.setFollowNum(0);
- user.setState(1);
- userRepository.save(user);
- }
- }
复制代码 运行测试类
查看效果
- @Test
- public void testFindAll(){
- List<User> all = userRepository.findAll();
- all.forEach(user -> System.out.println("user = " + user));
- }
复制代码
加上service层
- package com.cqh.service;
- import com.cqh.entity.User;
- import java.util.List;
- /**
- * @author cqh
- * @date 2024/1/14
- * @Description
- */
- public interface UserService {
- void save(User user);
- List<User> findAll();
- void deleteById(String id);
- void update(User user);
- User findById(String id);
- }
复制代码- package com.cqh.service.impl;
- import com.cqh.dao.UserRepository;
- import com.cqh.entity.User;
- import com.cqh.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.List;
- /**
- * @author cqh
- * @date 2024/1/14
- * @Description
- */
- @Service
- public class UserServiceImpl implements UserService {
- @Autowired
- private UserRepository userRepository;
- /**
- * 保存
- *
- * @param user
- */
- public void save(User user) {
- userRepository.save(user);
- }
- /**
- * 更新
- *
- * @param user
- */
- public void update(User user) {
- userRepository.save(user);
- }
- /**
- * 根据id删除
- *
- * @param id
- */
- public void deleteById(String id) {
- userRepository.deleteById(id);
- }
- /**
- * 查询所有
- *
- * @return
- */
- public List<User> findAll() {
- return userRepository.findAll();
- }
- /**
- * 根据id查询
- *
- * @param id
- * @return
- */
- public User findById(String id) {
- return userRepository.findById(id).get();
- }
- }
复制代码 测试成功

其他的改删都可以

- package com.cqh;
- import com.cqh.dao.UserRepository;
- import com.cqh.entity.User;
- import com.cqh.service.UserService;
- 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.test.context.junit4.SpringJUnit4ClassRunner;
- import java.util.Date;
- import java.util.List;
- /**
- * @author cqh
- * @date 2024/1/14
- * @Description
- */
- @RunWith(SpringJUnit4ClassRunner.class)
- @SpringBootTest
- public class MongoDBTest {
- @Autowired
- private UserRepository userRepository;
- @Autowired
- private UserService userService;
- @Test
- public void testSave(){
- User user = new User();
- user.setName("张三");
- user.setAge(18);
- user.setAddress("重庆");
- user.setCreateTime(new Date());
- user.setFollowNum(0);
- user.setState(1);
- userRepository.save(user);
- }
- @Test
- public void testFindAll(){
- // List<User> all = userRepository.findAll();
- List<User> all = userService.findAll();
- all.forEach(user -> System.out.println("user = " + user));
- }
- @Test
- public void testFindById() {
- User user = userService.findById("65a3bf0a72042e8240b1c496");
- System.out.println(user);
- }
- @Test
- public void testUpdate() {
- User user = new User();
- user.setId("65a3bf0a72042e8240b1c496");
- user.setAge(10);
- user.setName("ddd");
- user.setState(1);
- user.setFollowNum(0);
- user.setCreateTime(new Date());
- userService.update(user);
- }
- @Test
- public void testDelete() {
- userService.deleteById("65a3bf0a72042e8240b1c496");
- }
- }
复制代码 方法命名规范查询
根据启用状态和性别查询
Repository中编写如下代码
Service中添加代码
ServiceImpl
MongoTemplate
现在有个需求,我们必要给某个用户的关注量+1,下面的代码是实现方案
- public void incrFollowCount(String id) {
- User user = userRepository.findById(id).get();
- user.setFollowNum(user.getFollowNum() + 1);
- userRepository.save(user);
- }
复制代码 该方案实现起来虽然简单,但是性能不高。
我们只必要给关注量+1,并不必要姓名、地址等这些数据,因此也就没必要查询出这些字段,乃至于根本就不必要查询操作,直接更新就可以了。
我们可以使用MongoTemplate办理这个需求。
- public void incrFollowCount(String id) {
- // 构造查询对象
- Query query = Query.query(Criteria.where("_id").is(id));
- // 构造更新对象
- Update update = new Update();
- // follow字段+1
- update.inc("followNum");
- // 执行update
- mongoTemplate.updateFirst(query, update, User.class);
- }
复制代码
分页查询
分页查询主要涉及两个类。一个是Page,一个是Pageable
- /**
- * 根据名称分页查询
- *
- * @param age
- * @param page
- * @param size
- * @return
- */
- public Page<User> findByAgePage(Integer age, int page, int size) {
- // 构造分页对象
- PageRequest pageRequest = PageRequest.of(page - 1, size);
- return userRepository.findByAge(age, pageRequest);
- }
复制代码
- @Test
- public void testFindByAgePage() {
- Page<User> users = userService.findByAgePage(18, 1, 2);
- System.out.println("总条数:" + users.getTotalElements());
- System.out.println("总页数:" + users.getTotalPages());
- System.out.println("本页数据:");
- List<User> userList = users.getContent();
- for (User user : userList) {
- System.out.println(user);
- }
- }
复制代码 实际开辟中我们大概会必要可以或很多条件分页查询,上面的场景大概不满足需求。使用MongoTemplate也可以办理分页题目
- /**
- * 使用MongoTemplate分页查询
- *
- * @param page
- * @param size
- * @param user
- * @return
- */
- public List<User> findPageByTemplate(int page, int size, User user) {
- // 构造一个查询对象
- Query query = new Query();
- // 设置参数
- if (!StringUtils.isEmpty(user.getName())) {
- query.addCriteria(Criteria.where("name").regex(user.getName() + ".*"));
- }
- if (user.getAge() != null) {
- query.addCriteria(Criteria.where("age").lt(user.getAge()));
- }
- if (user.getSex() != null) {
- query.addCriteria(Criteria.where("sex").is(user.getSex()));
- }
- // 跳过多少条
- query.skip((page - 1) * size);
- // 取出多少条
- query.limit(size);
- // 构造排序对象
- Sort.Order order = new Sort.Order(Sort.Direction.DESC, "age");
- // 设置排序对象
- query.with(Sort.by(order));
- return mongoTemplate.find(query, User.class);
- }
复制代码 @Query注解
我们使用SpringDataJpa操作MySql的时间,尽管JPA已经非常强大,仍然避免不了手写sql的场景。
SpringDataMongoDB也存在类似的情况,因此我们大概会必要手写MongoDB的查询语句,使之操作更加灵活。
手写查询语句可以使用 @Query 注解。
需求1:根据 state 和 age 查询
这里我们必要使用 ?数字占位符 表达式来取出参数中指定位置的值,占位符从0开始。
- /**
- * 根据state和age查询
- *
- * @param state
- * @param age
- * @return
- */
- @Query("{ state: ?0, age: ?1 }")
- List<User> selectEnableUserByAge(Integer state, Integer age);
复制代码 需求2:偶尔间我们的参数大概过多,条件也大概不同,我们想传入一个实体类进行查询,直接取出实体类中的属性进行条件构造。
这里我们必要使用 SpEL 表达式,格式:?#{} 括号中使用 [下标] 来取出指定位置的参数,如 ?#{[0]} 则取出第一个参数。之后直接取出参数中的指定属性即可,如 ?#{[1].age} 就是取出第二个参数的age属性。
现在我们必要查询 性别为女,大概年岁在18岁以下的全部启用中的用户
- /**
- * 根据实体类查询
- * 根据性别或者年龄,和状态查询
- *
- * @param user
- * @return
- */
- @Query("{ state: ?#{[0].state}, $or: [ {sex: ?#{[0].sex}}, {age: { $lt: ?#{[0].age} }} ] }")
- List<User> selectByEntity(User user);
复制代码 同时,如果我们只想获取指定的字段,我们还可以使用第二个参数 fields 来进行投影查询
- /**
- * 根据实体类查询
- * 根据性别或者年龄,和状态查询
- *
- * @param user
- * @return
- */
- @Query(value = "{ state: ?#{[0].state}, $or: [ {sex: ?#{[0].sex}}, {age: { $lt: ?#{[0].age} }} ] }",
- fields = "{ name:1, age:1 }")
- List<User> selectByEntity(User user);
复制代码 副本集
简介
MongoDB复制是将数据同步在多个服务器的过程。
复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以包管数据的安全性。复制还答应您从硬件故障和服务停止中规复数据。
通俗来讲,副本集就是多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且能当主库宕机时在不必要用户干预的情况下自动切换到其他备份的数据库作为主库。并且,还可以使用副本访问做读写分离。
副本集的使用可以提供冗余和高可用性,提高体系负载。
MongoDB中的复制
mongodb的复制至少必要两个节点。此中一个是主节点,负责处理客户端哀求,别的的都是从节点,负责复制主节点上的数据。
mongodb各个节点常见的搭配方式为:一主一从、一主多从。
主节点记录在其上的全部操作更改,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而包管从节点的数据与主节点同等。
MongoDB复制布局图如下所示:
客户端从主节点读取数据,在客户端写入数据到主节点时, 主节点与从节点进行数据交互保障数据的同等性。
主从复制和副本集的区别
主从复制和副本集的最大区别就是,副本集没有固定的主节点,整个集群会选出一个主节点,当主节点挂掉后,剩下的节点又会选出一个主节点。
副本集的脚色
副本集主要有两种类型和三种脚色
两种类型:
- 主节点(Primary):数据操作的主要毗连点,答应读和写操作
- 从节点(Secondaries):数据冗余备份节点,可以读或选举为主节点
脚色:
MongoDB主要有三种脚色
主要成员(Primary):主节点,主要接收全部的写操作
副本成员(Replicate):主从节点通过备份操作以维护雷同的数据集。只支持读操作,不支持写操作。拥有选举本领
仲裁者(Arbiter):不保留任何数据的副本,只具有选举作用。副本成员也可以作为仲裁者。
仲裁者永远是仲裁者,而主要成员与副本成员之间脚色大概会发生变化。副本成员大概会因为主要成员的宕机而转为主要成员。主要成员也大概因为宕机并重新修复后成为副本成员。
尽大概包管主节点+副本的个数是奇数,如许就不必要加仲裁者就可以满足大多数的投票
如果主节点+副本的个数是偶数,建议加一个仲裁者。
分片
MongoDB除了副本集以外,还支持分片集群。分片可以满足MongoDB数据量大量增长的需求。
当MongoDB存储海量的数据时,一台机器大概不足以存储数据,也大概不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库体系能存储和处理更多的数据。
概念
分片(偶尔间也叫分区)是一种跨多台机器分布数据的方法,是指将数据拆分,将其分散到不同的机器上,处理更多的负载。
分片有两种办理方案:垂直扩展和水平扩展。
垂直扩展:增加更多的CPU和存储资源来扩展容量。
水平扩展:将数据集分布在多个服务器上。水平扩展就是分片
为什么使用分片
- 复制全部的写入操作到主节点
- 延迟的敏感数据会在主节点查询
- 单个副本集限制在12个节点
- 当哀求量巨大时会出现内存不足。
- 本地磁盘不足
- 垂直扩展必要更多的钞本领
分片包罗的组件
上图中主要有如下所述三个主要组件:
- Shard:
分片,用于存储实际的数据块,实际生产环境中一个分片可以由多个副本集负担,防止主机单点故障
- Config Server:
设置服务器。存储几群的元数据和设置。从MongoDB3.4开始,设置服务器必须是副本集
- Query Routers:
路由,mongos充当查询路由器,在客户端和分片集群之间提供接口
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |