聊聊MongoDB中连接池、索引、事务

时间:2023-01-11 07:14:14

大家好,我是哪吒。

三分钟你将学会:

  1. MongoDB连接池的使用方式与常用参数
  2. 查询五步走,能活九十九?
  3. MongoDB索引与MySQL索引有何异同?
  4. MongoDB事务与ACID
  5. 什么是聚合框架?

聊聊MongoDB中连接池、索引、事务

在最开始接触MongoDB的时候,是通过 MongoDatabase database = new MongoClient("localhost", 27017).getDatabase("test"); 的方式连接MongoDB。

它会为每个请求创建一个新的连接,然后销毁,一般数据库的连接都是TCP连接,TCP是长连接,如果不断开,就会一直连着。

众所周知,新建一个数据库连接的代价是很大的,复用现有连接才是首选,连接池就是干这个的。

连接池 = 数据库连接的缓存

因此当需要新的连接时,就可以复用连接池中缓存的连接了。如果使用得当,连接池可以最大程度的降低数据库的新连接数量、创建频率。

可以通过Mongo.get方法获得DB对象,表示MongoDB数据库的一个连接。默认情况下,当执行完数据库的查询操作后,连接将自动回到连接池中,通过api中的finally方法,将连接归还给连接池,不需要手动调用。

MongoDB查询数据五步走

  1. MongoDB Client需要找到可用的MongoDB;
  2. Server MongoDB Client需要和 MongoDB Server建立 Connection;
  3. 应用程序处理线程从 Connection Pool中获取 Connection;
  4. 数据传输(获取连接后,进行 Socket 通信,获取数据);
  5. 断开 Collection;

聊聊MongoDB中连接池、索引、事务

MongoDB连接池的参数配置

#线程池允许的最大连接数
connectionsPerHost: 40
#线程池中连接的最大空闲时间
threadsAllowedToBlockForConnectionMultiplier: 20
#1、MongoDB Client需要找到可用的MongoDB Server所需要的等待时间
serverSelectionTimeout: 40000
#2、MongoDB Client需要和MongoDB Server建立(new)Connection
connectTimeout: 60000
#3、应用程序处理线程从Connection Pool中获取Connection
maxWaitTime: 120000
#自动重连
autoConnectRetry: true
#socket是否保活
socketKeepAlive: true
#4、数据传输(获取连接后,进行Socket通信,获取数据)
socketTimeout: 30000
slaveOk: true
dbName: ngo
#是否进行权限验证
auth: false
#用户名
username: ngo
#密码
password: 12345678

下面简单说一下MongoDB的索引

索引可以显著缩短查询时间,但是,使用索引也是有代价的,索引字段的增删改操作会花费更长时间,因为在更改数据时,除了更新文档数据,MongoDB还必须更新索引。这个和关系型数据库是一样的。MongoDB的索引机制和关系型数据库的索引机制大同小异。

要选择为哪些字段建索引,可以查看常用的查询以及那些需要快速执行的查询。

索引基数是指集合中某个字段有多少个不同的值

通常来说,一个字段的基数越高,这个字段上的索引就越有用。这是因为这样的索引能够迅速将搜索范围缩小到一个比较小的结果集。对于基数比较低的字段,索引通常无法排除大量可能的匹配项。

索引可以显著缩短查询时间,但是,使用索引也是有代价的,索引字段的增删改操作会花费更长时间,因为在更改数据时,除了更新文档数据,MongoDB还必须更新索引。这个和关系型数据库是一样的。MongoDB的索引机制和关系型数据库的索引机制大同小异。

要选择为哪些字段建索引,可以查看常用的查询以及那些需要快速执行的查询。

MongoDB内嵌文档是什么?

MongoDB允许深入文档内部,对内嵌字段和数组创建索引。内嵌对象和数组字段可以和*字段一起在符合索引中使用。

可以在内嵌文档的键上创建索引,方法与在普通键上创建索引相同。

在info中的address字段上建立索引。对子文档创建索引,只有进行与子文档字段顺序完全匹配的查询时,查询优化器才能使用"address"上的索引。

聊聊MongoDB中连接池、索引、事务

MongoDB事务是什么?

事务是数据库中处理的逻辑单元,包括一个或多个数据库操作,既可以是读操作,也可以是写操作,MongoDB支持跨个多操作、集合、数据库、文档和分片的ACID事务。

事务的关键:它要么都成功,要么都失败。

ACID是什么?

ACID是一个事务所需要具备的一组属性集合。

ACID是原子性atomicity、一致性consistency、隔离性isolation、持久性durability的缩写。

ACID事务可以确保数据和数据库状态的有效性,即使在出现断电或其它错误的情况下也是如此。

原子性确保了事务中的所有操作要么都被执行、要么都不被执行。

一致性确保可如果事务成功,那么数据库将从一个一致性状态转移到下一个一致性状态。

隔离性是允许多个事务同时在数据库中运行的属性。它保证了一个事务不会查看到任何其它事务的部分结果,这意味着多个事务并行运行于依次运行每个事务所获得的结果都相同。

持久性确保了在提交事务时,即使系统发生故障,所有数据也都会保持持久化。

当数据库满足所有这些属性并且只有成功的事务才会被处理时,它就被称为符合ACID的数据库。如果在事务完成之前发生故障,ACID确保不会更改任何数据。

MongoDB是一个分布式数据库,它支持跨副本集和跨分片的ACID事务。网络层增加了额外的复杂性。

MongoDB提供了两种API来使用事务

  • 第一种与关系型数据库类似(如start_transaction和commit_transaction),称为核心API;
  • 第二种称为回调API,一般推荐使用这种;

核心API不会为大多数错误提供重试逻辑,它要求开发人员为操作、事务提交函数以及所需的任何重试和错误逻辑手动编写代码。

与核心API不同,回调API提供了一个简单的函数,该函数封装了大量的功能,包括启动与指定逻辑会话关联的事务、执行作为回调函数提供的函数以及提交事务。回调API还提供了处理提交错误的重试逻辑。在MongoDB4.2中添加回调API是为了简化使用事务的应用程序开发,也便于添加处理事务错误的应用程序重试逻辑。

核心API和回调API的比较

核心API 回调API
需要显示调用才能启动和提交事务 启动事务、执行指定操作,然后提交(可在发生错误前终止)
不包含TransientTransactionError和UnknowTransactionCommitResult的错误处理逻辑,而是提供了为这些错误进行自定义处理的灵活性 自动为TransientTransactionError和UnknowTransactionCommitResult提供错误处理逻辑
要求为特定事务将显式的逻辑会话传递给API 要求为特定事务将显式的逻辑会话传递给API

聚合框架是什么?

聚合框架是MongoDB中的一组分析工具,可以对一个或多个集合中的文档进行分析。

聚合框架基于管道的概念,使用聚合管道可以从MongoDB集合获取输入,并将该集合中的文档传递到一个或多个阶段,每个阶段对输入执行不同的操作。每个阶段都将之前阶段输出的内容作为输入。所有阶段的输入和输出都是文档,可以称为文档流。

聊聊MongoDB中连接池、索引、事务

每个阶段都会提供一组按钮或可调参数,可以通过控制它们来设置该阶段的参数,以执行各种任务。

这些可调参数通常采用运算符的形式,可以使用这些运算符来修改字段、执行算术运算、调整文档形状、执行各种累加任务或其它各种操作。

常见的聚合管道包括匹配match、投射project、排序sort、跳过skip、限制limit。