参考 > MongoDB CRUD操作 > MongoDB CRUD概念 > 阅读隔离度,一致性和新近度
根据读取的关注点,客户端可以在持久写入之前看到写入结果:
"local"
或"available"
读关注的客户端都可以在向发布客户端确认写操作之前看到写操作的结果。"local"
或"available"
读取关注点的客户端可以读取数据,这些数据随后可能会在副本集故障转移期间回滚。对于多文档事务中的操作,在提交事务时,将保存在事务中进行的所有数据更改,并在事务外部可见。也就是说,一个事务在回滚其他事务时将不会提交其某些更改。
在提交事务之前,在事务外部看不到在事务中进行的数据更改。
但是,当一个事务写入多个分片时,并非所有外部读取操作都需要等待已提交事务的结果在所有分片上可见。例如,如果提交了一个事务,并且在分片A上可以看到写1,但是在分片B上仍然看不到写2,则外部读处于读关注状态
"local"
可以读取写1的结果而看不到写2。
读未提交是默认的隔离级别,适用于
mongod
独立实例以及副本集和分片群集。
对于单个文档,写操作是原子的。即,如果写操作正在更新文档中的多个字段,则读操作将永远不会看到仅更新了某些字段的文档。但是,尽管客户端可能看不到部分更新的文档,但未提交的读取意味着并发的读取操作仍可以在使更改持久化之前看到更新的文档。
对于独立mongod
实例,对单个文档的一组读取和写入操作是可序列化的。使用副本集,仅在没有回滚的情况下,对单个文档的一组读取和写入操作才能序列化
。
当单个写入操作(例如
db.collection.updateMany()
)修改多个文档时,每个文档的修改都是原子的,但整个操作不是原子的。
当执行多文档写操作时,无论是通过单个写操作还是通过多个写操作,其他操作都可能会交错。
对于需要对多个文档(在单个或多个集合中)进行读写原子性的情况,MongoDB支持多文档事务:
有关MongoDB中事务的详细信息,请参阅 事务页面。
重要
在大多数情况下,与单文档写入相比,多文档事务产生的性能成本更高,并且多文档事务的可用性不应代替有效的架构设计。在许多情况下, 非规范化数据模型(嵌入式文档和数组)对于您的数据和用例将继续是最佳的。也就是说,在许多情况下,对数据进行适当的建模将最大程度地减少对多文档交易的需求。
有关其他事务使用方面的注意事项(例如运行时限制和oplog大小限制),另请参见 生产注意事项。
在不隔离多文档写入操作的情况下,MongoDB表现出以下行为:
3.4版的新功能。
对于主服务器上的读取和写入操作,发出具有"linearizable"
读取关注的读取操作和具有"majority"
写入关注的写入操作使多个线程可以在单个文档上执行读取和写入,就好像单个线程实时执行了这些操作一样。也就是说,这些读写的相应计划被认为是线性的。
也可以看看
3.6版的新功能。
如果操作在逻辑上依赖于先前的操作,则这些操作之间存在因果关系。例如,基于指定条件删除所有文档的写入操作和验证删除操作的后续读取操作具有因果关系。
在因果一致的会话中,MongoDB按照尊重因果关系的顺序执行因果操作,并且客户观察到与因果关系一致的结果。
为了提供因果一致性,MongoDB 3.6启用了客户端会话中的因果一致性。因果一致的会话表示具有"majority"
读关注点的读操作和具有"majority"
写关注点的写操作的关联序列具有因果关系,这由它们的顺序反映出来。
应用程序必须确保一次只有一个线程在客户端会话中执行这些操作。
对于因果相关的操作:
客户端启动客户端会话。
重要
客户会话仅保证以下方面的因果一致性:
"majority"
; 也就是说,返回数据已被大多数副本集成员确认并且是持久的。"majority"
关注写操作 也就是说,写操作要求确认该操作已应用于大多数副本集的有投票权的成员。有关因果一致性和各种读写问题的更多信息,请参见 因果一致性和读写问题。
当客户端发出具有"majority"
读关注和写操作(具有
"majority"
写关注)的读取序列时
,客户端将会话信息包含在每个操作中。
对于与会话相关联的每个具有"majority"
读关注点的读操作和具有"majority"
写关注点的写操作,即使操作错误,MongoDB也会返回操作时间和集群时间。客户端会话跟踪操作时间和群集时间。
注意
对于未确认()的写操作,MongoDB不返回操作时间和集群时间。未经确认的写入并不表示任何因果关系。w: 0
尽管MongoDB在客户端会话中返回读操作和已确认写操作的操作时间和群集时间,但是只有具有"majority"
读关注的读操作
和具有"majority"
写关注的写操作
才能保证因果一致性。有关详细信息,请参见
因果一致性和读写问题。
关联的客户端会话跟踪这两个时间字段。
注意
不同会话之间的操作可以因果一致。MongoDB驱动程序和mongo
外壳程序提供了延长客户端会话的操作时间和集群时间的方法。因此,客户端可以提前群集时间和一个客户端会话的操作时间,使其与另一客户端会话的操作保持一致。
下表列出了因果一致会话提供的因果一致性保证,"majority"
涉及具有读关注的读取操作
和具有"majority"
写关注的写入操作。
保证金 | 描述 |
---|---|
阅读您的文章 | 读操作反映了在其之前的写操作的结果。 |
单调读 | 读取操作不会返回与先前读取操作相比更早的数据状态的结果。 例如,如果在会话中:
那么read 2无法返回write 1的结果。 |
单调写 | 必须在其他写入之前执行的写操作在这些其他写入之前执行。 例如,如果写入1必须先于写入2在会话,在写入时的数据的状态2 必须反映数据写入后的状态1。其他写入可以在写入1和写入2之间进行交错,但是写入2不能在写入1之前发生。 |
写跟读 | 在读操作之后执行读操作之后必须发生的写操作。即,写入时的数据状态必须包含之前的读取操作的数据状态。 |
这些保证适用于MongoDB部署的所有成员。例如,如果在因果一致的会话中发出具有"majority"
写关注点的写操作,
然后发出从secondary
具有"majority"
读关注点的辅助卷(即读首选项)
读取的读,则读操作将反映写操作之后的数据库状态。
因果一致的会话内的操作与会话外的操作不是隔离的。如果并发的写操作在会话的写操作和读操作之间交错,则会话的读操作可能返回反映在会话的写操作之后发生的写操作的结果。
该featureCompatibilityVersion
(FCV)必须设置为“3.6”或更大。要检查fCV,请运行以下命令:
有关更多信息,请参见查看FeatureCompatibilityVersion和
setFeatureCompatibilityVersion
。
小费
应用程序必须确保一次只有一个线程在客户端会话中执行这些操作。
客户端需要为MongoDB 3.6或更高版本更新的MongoDB驱动程序:
Java 3.6+ Python 3.6+ C 1.9以上 |
C#2.5以上 节点3.0+ Ruby2.5+ |
Perl 2.0以上 PHPC 1.4以上 Scala 2.2+ |
重要
因果一致的会话只能保证因读而"majority"
引起的读和因"majority"
写而引起的写的
因果一致性
。
考虑一个集合items
,该集合维护各种项目的当前和历史数据。只有历史数据具有非空end
日期。如果项目的sku
值更改,则具有旧sku
值的文档需要用end
日期更新
,此后,将使用当前sku
值插入新文档
。客户端可以使用因果一致的会话来确保更新在插入之前发生。
如果另一个客户端需要读取所有当前sku
值,则可以将群集时间和操作时间提前到另一个会话的群集时间和操作时间,以确保该客户端与另一个会话有因果关系,并在两次写入之后读取: