企业应用实战 之 MongoDB入门

课程内容

一、MongoDB的基本介绍

MongoDB是一个nosql数据库,它有高性能、无模式、文档型的特点。他是nosql数据库中功能最丰富,最像关系数据库的。

1、核心概念

MongoDB数据库的最小数据集,是由多个键值对有序组合的数据单元,类似于mysql的一行数据记录,一般由json格式指定;

由一组文档构成,类似于mysql的表,可以存放多行数据;

每个数据库都是独立的,有自己的用户,权限,独立存储集合,类似于mysql的库;

系统上运行的MongoDB的进程,类似于mysql实例;

2、特性

3、适用场景

MongoDB适用于 游戏,社交,物流,物联网,视频直播这些场景 。

二、MongoDB安装与使用

1、安装MongoDB

这里的安装是以Windows安装为例的,但实际生产场景大部分都是在linux进行部署。接下来我看介绍一下mongdb的安装步骤;

MongoDB官网:https://www.mongodb.com/try/download/community

1)Windows安装

下载:mongodb-windows-x86_64-5.0.14-signed.msi

安装:安装路径不能有中文、空格、以及其他特殊字符;

启动MongoDB服务:

在浏览器打开http://127.0.0.1:27017,有如下提示,则说明安装成功了

It looks like you are trying to access MongoDB over HTTP on the native driver port.

2)Linux安装

执行: wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-5.0.11.tgz

# 通过vi命令编辑以下文件   vi /etc/profile   # 在该文件中追加以下命令 # 解压完以后mongo的文件夹地址   export MONGODB_HOME=/opt/self/mongodb   export PATH=$PATH:$MONGODB_HOME/bin   # 刷新环境变量   source /etc/profile 
# 创建mongodb存储位置  mkdir mongodb-data   # 进入到创建的文件家中,创建数据和日志存储文件夹   mkdir data   mkdir logs# 启动mongodb,指定数据以及日志存储位置,在解压后的mongodb的bin目录下执行   mongod --dbpath /opt/self/mongodb-data/data --logpath /opt/self/mongodb-home/ogs/mongodb.log --fork  

3)连接mongodb

① 命令行

将mongosh-1.6.1-win32-x64.zip中bin目录下mongosh.exe和mongosh_crypt_v1.dll解压到MongoDB安装目录的bin目录下

# 如果是在本机测试,可以简化为mongosh
mongosh --host 127.0.0.1 --port 27017
# 通过以下命令查看当前存在的数据库
show dbs
show databases

注意:mongo在创建完成以后会默认存在admin,config,local这三个数据库,其中admin中存储的是mongodb的用户、角色等信息;config中存储的是分片集群基础信息;local中主要存储的是副本集的元数据

② 可视化工具

MongoDB的可视化工具有很多,比如安装过程中的MongoDB Compass、Navicat Premium 15、Robo

这里我们使用Navicat Premium 15连接演示一下:

安装与破解过程参考:resources/navicate15/Navicate15激活教程.docx

2、MongoDB基本命令【了解】

1) 切换或者创建库

-- 切换指定库,如果该库不存在,则创建该库,在切换到该库
use database;

2) 创建集合

-- 直接创建
db.createCollection(name)
-- 如果collection不存在,则会先创建collection,这是一种隐式创建方式
db.collection.insert({id:1})
-- 查询当前库中存在的集合
show tables

3) 文档的增删改查

-- 查询集合所有
db.collection.find()
-- 查询集合的第一个
db.collection.findOne()
-- 根据条件进行查询,支持传入两个参数
-- 第一个参数是过滤条件
-- 第二个是控制显示的数据列,1代表显示,0-代表不显示,如果不配置,默认显示所有
db.collection.find({id:1},{id:1,name:0})
-- 使用正则表达式,匹配姓名以a开头的数据
db.collection.find({name:/^a/})


-- 插入数据
db.collection.insert({id:1,name:"a"})
-- 批量插入数据
db.collection.insertMany([{id:1,name:"a"},{id:2,name:"b"}])


-- 覆盖更新,将id为一的这条数据更新为只有name=2,即使原数据存在sex=0,执行完以下语句以后,
-- 这条语句也会变成只有name=2
db.correction.update({id:1},{name:2})
-- 选择更新,只更新对应的字段,下面的语句只会吧id=1的数据中,name修改为2,其它不变
-- 但是它只会更新满足条件的第一条数据
db.correction.update({id:1},{$set:{name:2}})
-- 选择更新,将所有id=1的数据中的name变更为2,其它数据不变
db.correction.update({id:1},{$set:{name:2}},{multi:true})


-- 删除数据,删除id为1的数据
db.collection.remove({id:1})
-- 删除全部数据
db.collection.remove({})

4) 统计操作

-- 统计所有数据
db.collection.count()
-- 统计id为1的数据
db.collection.count({id:1})

5) 分页与排序

-- 查询前5条数据
db.collection.find().limit(5)
-- 查询跳过前5条的其它数据
db.collection.find().skip(5)

-- 分页查询,每页显示5条,查询第一页和第二页的数据
db.collection.find().skip(0).limit(5)
db.collection.find().skip(5).limit(5)

-- 排序,1-升序,-1-降序
db.collection.sort({id:1, age:-1})

6) 范围查找

-- $gt-大于,$lt-小于,$gte-大于等于,$lte-小于等于,$ne-不等于
-- 查询id大于10的数据
db.collection.find({id:{$gt:10}})
-- 查询id大于10小于30的数据,需要注意这里必须使用$and
db.collection.find({$and:[{id:{$gt:10}},{id:{$lt:30}}]})

-- 查询id是1和3的数据
db.collection.find({id:{$in:[1,3]}})

7) 索引操作

-- 创建索引,1-升序索引,-1降序索引
db.collection.createIndex({id:1})
-- 查看集合已经创建的索引
db.collection.getIndexs()
-- 移除指定索引
db.collection.dropIndex({id:1})
-- 移除集合的全部索引
db.collection.dropIndexes()

8) 加锁操作

# 加锁
db.collection.fsyncLock()
# 解锁
db.collection.fsyncUnlock()

9) 事务操作(mongodb不推荐使用事务)

# 插入多条数据
db.test_1.insertMany([{ id: 1 }, { id: 2 }]);
# 开启事务
var session = db.getMongo().startSession();
session.startTransaction();
# 获取需要修改的集合
var coll = session.getDatabase('test').getCollection("test_1");
# 进行数据更新
coll.updateOne({id: 1}, {$set: {name: "a"}});
# 获取的文档为id:1,name:a
coll.findOne({id: 1});
# 获取的文档为id:1
db.test_1.findOne({id: 1});
# 事务回滚或者提交
session.abortTransaction();

针对事务有以下几个注意点:

1、事务必须在60s内完成,超时将取消

2、涉及事务的分片不能使用仲裁节点

3、事务会影响chunk(在后面的分片集群中会介绍)的迁移效率。在chunk迁移过程中会导致事务提交失败

4、多文档事务中的读操作必须使用主节点

5、readConcern(在后文的复制集中会进行介绍)只应该在事务级别设置,不能设置在每次读写操作。

三、MongoDB集群【扩展】

1、复制集

复制集指的就是mongodb的集群,它的主要意义是用来实现mongodb的高可用。其结构为一主多从的结构。其中从节点分为三类:

1、从主节点进行数据复制,可以对外部提供数据读取,并且当主节点出现问题以后,可以参与主节点的选举;

2、只能从主节点进行数据复制,但是没有选举功能;

3、只存在选举功能,这类节点是不推荐使用的,造成资源浪费;

复制集具有以下的作用:

数据分发:这种是针对全球性网站类似的情况,将数据分发到不同的服务器,在读取时减少读取时间,提高读取效率;

读写分离:提高并发量,将不同类型的操作压力分到不同的节点上面;

异地容灾:当本地的数据中心出现问题时,切换到异地的数据中心上;

1.1、复制集的搭建

在这里简单介绍一下复制集的搭建,本文是在一台服务器上搭建三个mongodb节点来进行模拟,真实生产环境一个复制集的不同节点肯定是分布在不同的服务器上的。创建三个目录,分别为db1,db2,db3,在三个目录下添加mongod.conf配置文件:

# 日志文件
systemLog:
  # 日志为文件格式
  destination: file
  # 日志文件的存储路径,不同的节点需要配置不同的路径    每个节点对应自己的目录
  path: /data/db1/mongod.log
  logAppend: true
storage:
  # mongodb数据存储位置,不同的节点需要配置不同的路径  每个节点对应自己的目录
  dbPath: /data/db1
net:
  bindIp: 0.0.0.0
  # 当前节点的端口     每个节点对应自己的端口号
  port: 28017
replication:
  # 复制集名称
  replSetName: rs0
processManagement:
  fork: true

在启动时需要指定配置文件:

mongod -f /data/db1/mongod.conf
mongod -f /data/db2/mongod.conf
mongod -f /data/db3/mongod.conf

连接入作为主节点的mongodb,然后执行以下命令:

# 复制集的初始化
rs.initiate()
# 添加从节点
rs.add("centosvm:28018")
rs.add("centosvm:28019")
#查看当前复制集的状态
rs.status()

通过一下命令进行验证 :

# 在主节点插入一条数据
db.test.insert({ id:1 })

#在从节点执行一下命令
rs.slaveOk()
db.test.find()

接下来用一个最简单的主从结构介绍复制集,一主三从。如小图所示:

在这个赋值集中,数据的同步流程是:当主节点发生写操作时,它的写操作会被记录到oplog中,然后主节点将这个oplog推送给从节点,从节点通过在主节点上打开一个taiable游标读取oplog中的新数据,让后将数据同步到自己节点上,通过这种方式与主节点保持数据一致。

mongdb的复制集两两节点之间每2s发送一次心跳,如果5次心跳未收到,则判断为节点失联。如果失联的节点为主节点,此时就会发起选举,选出新的节点,选举是基于raft一致性算法实现,选举成功的必要条件是超过一半具有投票功能的节点存活。对于上面那个集群,当主节点失联,从节点必须有两个存活才能进行选举(注,复制集最多有50个节点,具有投票权额节点最多有7个)。

在进行选举的时候,能够选取为主节点的从节点必须具有以下的特点:

1)能够与更多的节点建立链接

2)oplog读取的位置最新

3)如果从节点设置了优先级,满足上述要求的优先级最高的节点

针对从节点,还有一些常见选项:

投票权:从节点默认具有投票权,可以关闭,单纯作为复制节点,参数为v;

优先级:优先级越高的节点在选举时同等条件下优先成为主节点,优先级为0的节点无法成为主节点,参数为priority;

隐藏:单纯作为数据备份,无法被应用访问,隐藏节点的优先级必须为0,参数为hidden;

延迟:在复制数据时,复制指定延迟时间之前的数据,与主节点保持时间差,常用来作为数据备份与恢复,参数为slaveDelay,单位为秒。

# 动态修改从节点的信息
conf=rs.conf()
conf.members[2].secondaryDelaySecs = 5
conf.members[2].priority = 0
rs.reconfig(conf)

1.2、复制集的写策略

复制集的写策略是通过writeConcern来进行配置的,他代表的是多少个节点确认完成才算是吸入成功。当数据写入主节点的时候,主节点会向从节点发送确认消息,如果从节点返回确认成功,才算一个从节点完成了确认,接下来主节点会再向从节点发送写入消息。如下图:

writeConcern的配置方式为:writeConcern:{w:n},你的赋值规则如下:

0:不关心写入结果,当应用发送写入命令以后,直接返回成功;

1:当应用发送写入命令以后,只要写入主节点,则返回成功;

n:大于1小于总结点的一个数值,代表写入主节点以后,需要n-1个节点确认成功,才返回成功;

majority:需要保证大多数节点完成确认,即超过总结点数的一半,才返回写入成功,这种方式为推荐方式;

all:全部节点完成确认,才会返回成功;

在写操作这里还有一个特殊的日志文件journal日志文件,它类似于关系型数据库中的事务日志。它的作用为mongodb数据库由于故障宕机以后的快速恢复。设置参数为j,值为true时代表数据要写入journal日志文件才算成功;false代表写操作记录到内存即可。开启该配置以后,肯定会影响一部分写性能,但是它有利于数据库的快速恢复,建议生产环境进行开启。参考下图:

1.3、复制集的读策略

在复制集中只要节点不是隐藏节点或者仅投票节点,这些节点是都可以向外部提供读取权限的,那么我们在读取的时候,应该从哪个节点进行读取呢?这需要我们根据具体的业务情况进行策略配置,配置参数为readPreference。它有一下几种值可供选择:

primary:只从主节点进行读取,这是mongodb的默认值;

primaryPreferred:优先从主节点读取,如果当前主节点不可用,则选择从节点读取;

secondary:只选择从节点进行读取;

secondaryPreferred:优先选择从节点读取,如果从节点不可用,则从主节点读取;

nearest:选择最近的节点,这里的最近指的是地理位置。

这些策略分别适用的场景为:primary/primaryPreferred:对数据实时性要求较高的业务场景,因为从节点有一个数据复制的过程,会造成数据延迟;secondary/secondartPreferred:适用查询历史数据的业务场景,其中secondary也适用于报表生成这类需要耗费大量资源的业务场景;nearest:适用于地域性较广的应用,进行就近读取,减少传输时间。

readPreferred的配置方式有三种,如下:

#在配置文件中的mongdb连接串后添加对应参数mongodb://host1:27107,host2:27107/?replicaSet=rs&readPreference=secondary#在java代码中MongoCollection.withReadPreference(ReadPreference readPref)#在xshell控制台中db.collection.find().readPref( "secondary")   

上面的这种方式,只能指定一类节点,主从节点。但是在实际生产中可能需要根据硬件配置,业务场景来区分要读取哪些节点。这是我们可以通过给不同的mongodb节点打上不同的tag来区分,方式如下:

# 给mongodb打tag
conf = rs.conf()
conf.members[1].tags = {"type" : "a" }
rs.reconfig(conf)

#应用程序的mongodb配置文件
mongodb://host1:27107,host2:27107/?replicaSet=rs&type=a

上面介绍了我们要从哪个节点读取数据的方式。但是节点上的那些数据是可以读取的呢?这就需要用到另一个参数readConcern。这个参数的配置值类似于数据库中的隔离级别。它有一下的策略配置,他们的隔离级别由上到下越来越强:

available:读取所有可用的数据,可以直接查询到写入复制集的数据;

local:读取所有可用且属于当前分片的数据,可以直接查询到该分片的数据;

majority:读取在大多数节点上提交的数据,使用该策略可以有效的避免脏读的问题。 majority采用mvcc机制来保证数据的读取。通过维护多个快照来链接不同的版本,每个被大多数节点确认过的版本都将是一个快照,快照持续到不再使用的时候才会进行删除。因为该策略是需要写入操作需要大多数节点完成确认,才能够被读取,当本次写入没有被大多数节点确认,主节点就发生回滚,那么本次写入对其它应用是不可见的;

linearizable:可线性化读取文档;

snapshot:读取最近快照中的数据,即每次读取都是从同一个快照中进行读取,那么也就避不会出现脏读,不可重复读以及幻读。下面看一个可重复的例子:

# 开启事务,并且将readConcern设置为快照
var session = db.getMongo().startSession();
session.startTransaction({readConcern: {level: "snapshot"},writeConcern: {w: "majority"}});
var coll = session.getDatabase('test').getCollection("test_1");、
# 读取id为1的数据,获得的文档为id:1
coll.findOne({id: 1});
# 不通过事务对id为1的数据进行更新 
db.tx.updateOne({id: 1}, {$set: {name: "b"}});
# 事务外读取id为1的数据,获得的文档为id:1,name:b
db.tx.findOne({id: 1});
# 事务内再次读取id为1的数据,获取的文档为id:1,它与第一次读时用的是同一个快照,所以两次读取是一样的
coll.findOne({id: 1}); 
session.abortTransaction();

2、分片集群

分片集群可以理解为是有多个复制集组成一个可以横向扩展的集群,每个复制集中存储不同范围的数据。分片集群主要是为了解决当下数据量日益增大,当一个节点存储大量数据,在进行数据恢复时需要的时间更大的情况以及解决全球化网站数据的存储以及访问问题。我们先来看一下分片集群的架构图,如下:

路由节点:提供分片集群的统一入口,一个mongodb节点即可满足要求,但是为了高可用,还是部署两台,因为它只是起到一个路由转发的功能,不需要进行存储大量数据,使用低配的服务器即可。

配置节点:配置节点的架构就是一个普通的复制集,提供集群元数据的存储,分片数据分布的映射。我们一般采用hash的方式作为分片依据,如果使用范围作为分片标准,会导致数据分布不均匀。

数据节点:数据节点以复制集作为存储单位,每个数据节点的数据是不重复的。一个数据节点就是1片,最大能达到1024分片。当数据量越来越大时,我们可以通过添加数据节点的方式进行横向扩容。每个分片的大小最好不要超过3T,尽可能保证2T每片。

分片数量可以由一下三个维度来进行计算,然后取其最大值:

1)总存储量/单台服务器容量;

2)工作集大小/单台服务器硬盘 * 0.6;

3)并发总数/单服务器并发数 * 0.7

下面介绍一下分片集群中的一些概念:

shard key:片键,文档中的一个字段;

doc:文档,包含shard key的一行数据;

chunk:块,包含多个文档;

shard:分片,包含多个chunk;

cluster:集群,包含多个cluster;

分片集群的一个好处就是可以进行动态扩容,当我们进行动态扩容时,由于分片变多,原有数据的存储位置就需要发生变更,此时就会发生chunk的移动,这就是mongodb的自动均衡机制。

四、MongoDB的数据备份【扩展】

mongodb的数据备份方式有两种:延迟节点备份以及全量备份+oplog。接下来我们做一个简单的介绍,一般这些工作是由运维完成。

1、 延迟节点备份

在上面的介绍中,我们知道从节点可以配置延迟同步时间,我们可以利用这一机制进行数据备份,能够让主节点恢复到指定时间之前的状态。这种情况适用于误操作时进行数据恢复。

此时我们可以利用节点2以及oplog,将主节点的数据恢复到安全范围内的任意一个节点的数据状态。

2、 全量备份+oplog

全量备份的方式有以下三种:

复制文件:复制数据库文件,在复制文件的时候需要先关闭或者锁定数据库,该复制过程要在从节点上完成,最好是设置为hidden的节点,这样对整个应用不会产生影响;

文件快照:mongodb支持使用文件快照直接获取数据库某一时刻的镜像,快照过程不用统计,但是必须要要与journal在一起;

mongodump:最灵活的一种备份方式,但是消耗时间长。在t1时间点进行备份,会在t3时间点备份完成,索引mongodunp备份的文件不是某一个时间点的数据,而是一个时间段的数据。

当我们要进行数据恢复时,可以找到离恢复时间点最近的一次全量备份,然后再加上这段时间范围之内的oplog,即可完成数据恢复。如果全量备份的频率较高,并且对数据的完整性要求不高的话,可以只恢复到最近的一次全量备份。

五、SpringBoot整合MongoDB【重要】

1、环境搭建

1)创建项目springboot-mongodb-demo

2)导入依赖


    org.springframework.boot
    spring-boot-starter-parent
    2.2.5.RELEASE



    
    
        org.springframework.boot
        spring-boot-starter-data-mongodb
    
    
    
        org.projectlombok
        lombok
    
    
    
        org.springframework.boot
        spring-boot-starter-web
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

3)创建mongodb用户

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

4)yml配置

spring:
  application:
    name: springboot-mongodb-demo
  data:
    mongodb:
      authentication-database: admin    # 登录用户所在的数据库
      host: 127.0.0.1                   # 数据库的ip地址
      port: 27017                       # MongoDB端口号
      username: wuchangyong             # 用户名
      password: "123456"                # 用户密码   必须加上双引号
      database: test                    # 指定使用的数据库,若不存在该库会自动创建

logging:
  level:
    org.springframework.data.mongodb.core: debug   #控制台输出日志记录

5)启动类

package cn.itsource.mongodb_demo;

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);
    }

}

2、代码操作

1)domain实体类

/**
 * SpringDataMongoDB会自动以当前domain实体类名称作为数据集合名称,相当于表名称
 *   若添加了@Document("employee")注解,也可指定其他名称
 *   @Document 表示一个文档,实则是转化为json格式的字符串 与SpringDataElasticsearch的文档实体类一致
 */
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)   //链式操作设置对象属性值
@Data
@Document("employee")
public class Employee {
    @Id// 必须指定id列
    private Long id;

    private String name;

    private Integer age;

    private String phone;

    private Date birthDay;
}

2)dao层接口

这里的dao层接口与SpringDataJpa、SpringDataElasticsearch都是一致的写法。

/**
 * 这种写法不需要实现类,很显然和我们之前讲的都一样采用了动态代理。
 * 两个泛型:实体类和主键字段类型
 */
public interface EmployeeRepository extends MongoRepository{

}

3、基本CRUD

1)测试新增文档

@SpringBootTest
@RunWith(SpringRunner.class)
public class DemoApplicationTests {

    @Autowired
    private EmployeeRepository employeeRepository;

    /**
     * 测试新增文档
     * @throws Exception
     */
    @Test
    public void testSave() throws Exception{
        Employee employee = new Employee()
                .setId(1L)
                .setName("张三丰")
                .setAge(22)
                .setBirthDay(new Date())
                .setPhone("18996157300");
        employeeRepository.save(employee);
    }

}

2)测试修改文档

/**
 * 测试修改文档
 *  save方法传入的实体对象
 *  其id在mongodb中存在就是修改,不存在就是新增
 * @throws Exception
 */
@Test
public void testSave2() throws Exception{
    Employee employee = new Employee()
        .setId(1L)
        .setName("张三丰123")
        .setAge(33)
        .setBirthDay(new Date())
        .setPhone("18996157301");
    employeeRepository.save(employee);
}

3)通过id获取文档

/**
 * 通过文档id查询
 * @throws Exception
 */
@Test
public void testFindById() throws Exception{
    System.out.println(employeeRepository.findById(1L).get());
}

4)通过id删除文档

/**
 * 通过文档id删除
 * @throws Exception
 */
@Test
public void testDeleteById() throws Exception{
    employeeRepository.deleteById(1L);
}

4、高级查询+分页+排序

1)where is

/**
 * 条件查询
 *  where...is...
 * @throws Exception
 */
@Test
public void testQueryByWhereIs() throws Exception{
    Query query = new Query();
    // where...is... 相当于 where ? = ?
    query.addCriteria(Criteria.where("age").is(12));
    Employee employee = mongoTemplate.findOne(query, Employee.class);
    System.out.println(employee);
}

2)where in

/**
 * 条件查询
 *  where...in...
 * @throws Exception
 */
@Test
public void testQueryByWhereIn() throws Exception{
    List ages = Arrays.asList(11,12,22,33);
    Query query = new Query();
    // where...in... 相当于 where ? in (?)
    query.addCriteria(Criteria.where("age").in(ages));
    List employees = mongoTemplate.find(query, Employee.class);
    System.out.println(employees);
}

3)字符模糊匹配

/**
* 字符串模糊查询
*  where...regex...
* @throws Exception
*/
@Test
public void testQueryByLike() throws Exception{
    Query query = new Query();
    // where...regex... 相当于 where ? like ?
    query.addCriteria(Criteria.where("name").regex("张"));
    List employees = mongoTemplate.find(query, Employee.class);
    System.out.println(employees);
}

4)范围查询

/**
 * 范围查询
 *  where...gte...lte...
 *  gte表示大于等于  lte表示小于等于   gt表示大于   lt表示小于
 * @throws Exception
 */
@Test
public void testQueryByRange() throws Exception{
    Query query = new Query();
    // where...gte... lte 相当于 where ? >= ? and ? <= ?
    query.addCriteria(Criteria.where("age").gte(12).lte(33));
    List employees = mongoTemplate.find(query, Employee.class);
    System.out.println(employees);
}

5)不返回指定字段

/**
 * 指定字段不返回
 * @throws Exception
 */
@Test
public void testQueryExculdeFields() throws Exception{
    Query query = new Query();
    //exclude表示排除
    query.fields().exclude("age");
    List employees = mongoTemplate.find(query, Employee.class);
    System.out.println(employees);
}

6)分页查询+排序

/**
 * 分页查询+排序
 * @throws Exception
 */
@Test
public void testQueryPageAndSort() throws Exception{
    Query query = new Query();
    //分页:当前页码从0开始
    query.with(PageRequest.of(0, 2));
    //排序:Sort.Direction.ASC表示升序,Sort.Direction.DESC表示降序
    query.with(Sort.by(Sort.Direction.DESC, "age"));
    List employees = mongoTemplate.find(query, Employee.class);
    System.out.println(employees);
}
展开阅读全文

页面更新:2024-03-08

标签:快照   节点   集群   备份   实战   入门   事务   操作   方式   文档   数据库   数据   企业

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top