大家好,我是书生剑,最近项目在使用MongoDB作为图片和文档的存储数据库,为啥不直接存MySQL里,还要搭个MongoDB集群,麻不麻烦? 让我们一起,一探究竟,继续学习MongoDB的事务、连接池以及聚合框架,实现快速入门,丰富个人简历,提高面试level,给自己增加一点谈资,秒变面试小达人,BAT不是梦。 一、MongoDB 不支持事务?一些第三方文章将 MongoDB 描述成 BASE 数据库。BASE 是指“基本可用、软状态、最终一致”。 但这不是真的,从来都不是!MongoDB 从来都不是“最终一致”的。对主文档的读写是强一致性的,对单个文档的更新始终是原子的。软状态是指需要持续不断的更新数据,否则数据就会过期,但 MongoDB 并非如此。 最后,如果太多的节点不可用,无法达成仲裁,MongoDB 将进入只读状态(降低可用性)。这是有意这么设计的,因为这样可以确保在出现问题时保持一致性。 MongoDB 是一个 ACID 数据库。它支持原子性、一致性、隔离性和持久性。 对单个文档的更新始终是原子的,从 4.0 版本开始,MongoDB 也支持跨多个文档和集合的事务。从 4.2 开始,甚至支持分片集群的跨分片事务。 虽然 MongoDB 支持事务,但在使用它时仍然要谨慎。事务是以性能为代价的,而且由于 MongoDB 支持丰富的分层文档,如果你的模式设计正确,就没有必要经常跨多个文档更新数据。 二、什么是事务?事务是数据库中处理的逻辑单元,包括一个或多个数据库操作,既可以是读操作,也可以是写操作,MongoDB支持跨个多操作、集合、数据库、文档和分片的ACID事务。 事务的关键:它要么都成功,要么都失败。 三、ACID的定义ACID是一个事务所需要具备的一组属性集合。 ACID是原子性atomicity、一致性consistency、隔离性isolation、持久性durability的缩写。 ACID事务可以确保数据和数据库状态的有效性,即使在出现断电或其它错误的情况下也是如此。 原子性确保了事务中的所有操作要么都被执行、要么都不被执行。 一致性确保可如果事务成功,那么数据库将从一个一致性状态转移到下一个一致性状态。 隔离性是允许多个事务同时在数据库中运行的属性。它保证了一个事务不会查看到任何其它事务的部分结果,这意味着多个事务并行运行于依次运行每个事务所获得的结果都相同。 持久性确保了在提交事务时,即使系统发生故障,所有数据也都会保持持久化。 当数据库满足所有这些属性并且只有成功的事务才会被处理时,它就被称为符合ACID的数据库。如果在事务完成之前发生故障,ACID确保不会更改任何数据。 MongoDB是一个分布式数据库,它支持跨副本集和跨分片的ACID事务。网络层增加了额外的复杂性。 四、如何使用事务MongoDB提供了两种API来使用事务。
核心API不会为大多数错误提供重试逻辑,它要求开发人员为操作、事务提交函数以及所需的任何重试和错误逻辑手动编写代码。 与核心API不同,回调API提供了一个简单的函数,该函数封装了大量的功能,包括启动与指定逻辑会话关联的事务、执行作为回调函数提供的函数以及提交事务。回调API还提供了处理提交错误的重试逻辑。在MongoDB4.2中添加回调API是为了简化使用事务的应用程序开发,也便于添加处理事务错误的应用程序重试逻辑。 核心API和回调API的比较
五、重要参数简介在MongoDB事务中有两种限制,第一种是时间,控制事务的运行时间、事务等待获取锁的时间以及所有事务运行的最长时间;第二种是MongoDB的oplog条目和单个条目大大小限制; 1、时间限制事务的默认最大运行时间是1分钟。可以通过修改 要显式设置事务的时间限制,建议在提交事务时指定maxTimeMS参数。如果maxTimeMS没有设置,那么将使用 事务等待获取其操作所需锁的默认最大时间是 5 毫秒。可以通过修改
2、oplog大小限制MongoDB会创建出与事务中写操作数量相同的oplog数目。但是,每个oplog条目必须在16MB的BSON文档大小限制之内。 六、连接池 = 数据库连接的缓存在最开始接触MongoDB的时候,是通过 MongoDatabase database = new MongoClient("localhost", 27017).getDatabase("test");的方式连接MongoDB。 它会为每个请求创建一个新的连接,然后销毁,一般数据库的连接都是TCP连接,TCP是长连接,如果不断开,就会一直连着。 众所周知,新建一个数据库连接的代价是很大的,复用现有连接才是首选,连接池就是干这个的。 因此当需要新的连接时,就可以复用连接池中缓存的连接了。如果使用得当,连接池可以最大程度的降低数据库的新连接数量、创建频率。 可以通过Mongo.get方法获得DB对象,表示MongoDB数据库的一个连接。默认情况下,当执行完数据库的查询操作后,连接将自动回到连接池中,通过api中的finally方法,将连接归还给连接池,不需要手动调用。 1、MongoDB查询数据五步走
2、MongoDB连接池的参数配置
七、聚合框架聚合框架是MongoDB中的一组分析工具,可以对一个或多个集合中的文档进行分析。 聚合框架基于管道的概念,使用聚合管道可以从MongoDB集合获取输入,并将该集合中的文档传递到一个或多个阶段,每个阶段对输入执行不同的操作。每个阶段都将之前阶段输出的内容作为输入。所有阶段的输入和输出都是文档,可以称为文档流。 每个阶段都会提供一组按钮或可调参数,可以通过控制它们来设置该阶段的参数,以执行各种任务。 这些可调参数通常采用运算符的形式,可以使用这些运算符来修改字段、执行算术运算、调整文档形状、执行各种累加任务或其它各种操作。 常见的聚合管道包括匹配match、投射project、排序sort、跳过skip、限制limit。 八、MongoDB文档格式设计文档中表示数据的方式,在进行文档格式设计时,首先需要了解查询和数据访问的方式。 1、限制条件比如最大文档大小为16MB。 2、查询和写入的访问模式通过了解查询的运行时间和频率,识别出最常见的查询,一旦确定了这些查询,就应该尽量减少查询的数量,并在文档设计中确保一起查询的数据存储在同一个文档中。 这些查询中未使用的数据应该存放在不同的集合中。需要考虑是否可以将动态数据(读/写)和静态数据(读)分离开。在进行文档格式设计时,提高最常见查询的优先级会获得最佳的性能。 3、关系类型根据业务逻辑、文档之间的关系来考虑哪些数据是相关的,确定使用嵌入还是引用。需要弄清楚如何在不执行其它查询的情况下引用文档,以及当关系发生变化时需要更新几个文档。还要考虑数据结构是否易于查询。 4、范式化与反范式化
如何选择范式化与反范式化,范式化的写入速度更快,而反范式化的读取速度更快,因此需要根据应用程序的实际需求进行权衡。 5、内嵌数据和引用数据对比
6、优化数据操作优化读操作通常包括正确的索引和单个文档中返回尽可能多的数据; 优化写操作通常包括减少索引数量、尽可能的提高更新效率; 通过删除旧数据进行优化: 第一种方式是通过固定集合实现; 第二种是使用TTL集合。TTL集合可以更精确的控制删除文档的时间,但在写入量过大的集合中操作速度不够快,通过遍历TTL索引来删除文档。 第三种方式是分库分表。每个月的文档单独使用一个集合。这种方式实现起来更加复杂,因为需要使用动态集合或数据库名称,可能需要查询多个数据库。 九、小结
|