翻译或纠错本页面

读隔离、一致性和时近性

隔离的保证

读的无限制性

在MongoDB中客户端可以在写操作:term:`durable`之前看到写的结果:

  • 不管 write concern 如何,其它客户端使用:readconcern:`“local”`(这是默认的)readConern可以在写操作通知到发出请求的客户端之前看到写操作的结果。

  • 客户端使用:readconcern:“local”`(默认的)readConcern可以读到可能在接下来被:doc: `rolled back </core/replica-set-rollbacks> 的数据。

读的无限制性是读的默认隔离级别,并且对于:program:`mongod`单节点实例以及复制集和分片集群都是一样的。

读的无限制性与单个文档的原子性

写操作对于单个文档是具有原子性的,这就是说如果一个写正在一个文档中更新多个字段,一个读取者将不会看到只有部分的字段被更新的结果。

对于一个单节点:program:`mongod`实例,一系列对于单个文档的读和写操作是顺序的。对于复制集*只有*在缺少回滚的情况下才会对单个文档的一系列操作具有顺序性。

尽管读取者不可能看到*部分*更新的文档,但是读的无限制性意味着并发的读取者还是可以在更新:term:`durable`之前看到已经更新的文档。

读的无限制性与多个文档写

当单个写操作更改多个文档时,更改每个文档是具有原子性的,但是整个操作是没有原子性的而且其他操作可能会参杂其中。但是您可以使用:update:`$isolated`*隔离*单个写操作更改多个文档。

Without isolating the multi-document write operations, MongoDB exhibits the following behavior:

  1. “无时间点”的读操作。假设一个读操作在时间*t*:sub:`1`开始读取文档。接下来一个时间*t*:sub:`2`写操作更新了这个文档。这个读操作可能看到的文档是已经更新后的版本,因此没有“时间点”的快照数据可以读取。

  2. “无序性”操作。假设一个读操作读取一个文档*d*1`在时间*t*:sub:`1,并且紧接着一个写操作更新*d*1`在晚些时候的*t*:sub:`3。这里引入了一个读写依赖,如果操作是有顺序的,读操作一定是在写操作之前。但是假设写操作更新了文档*d*2`在时间*t*:sub:`2`并且读操作紧接着读取了*d*:sub:`2`在更晚些的时间*t*:sub:`4。这里又引入了写读依赖这将使读操作要在写操作*之后*按照顺序执行。这样的一个循环依赖将导致整个顺序化无法实现。

  3. Reads may miss matching documents that are updated during the course of the read operation.

使用:update:`$isolated`操作,一个写操作将影响多个文档并能够保证在第一个文档写操作开始其他进程不会参杂在其中。这将保证不会有客户端看到更新直到写操作完成或者出现错误。

:update:`$isolated`在:term:`sharded clusters <sharded cluster>`**不**起作用

一个隔离的写操作不提供”所有或者全部没有”的原子性。这就是说在写的过程中如果有错误产生不会将所有的在错误产生之前的更新全部回滚。

注解

:update:`$isolated`操作将使写操作在集合上获得一个排他锁,*甚至对于文档级别的锁存储引擎*比如WiredTiger也是这样处理的。这也就是说在执行:update:`$isolated`操作运行期间会导致WiredTiger单线程运行。

游标快照

MongoDB的游标可以在某些情况下不止一次返回同一个文档。当一个游标返回文档时其他操作有可能会参杂在查询之中。如果这些操作有些是:doc:updates </tutorial/update-documents> 将导致文档移除(如果使用MMAPv1存储引擎文档的增长会导致这样的情况产生)或者修改了查询中使用到的索引,这样有可能导致游标会返回同一个文档多次。

在非常特殊的案例中,您可以使用:method:`cursor.snapshot()`方法阻止游标返回同一个文档多次。:method:`~cursor.snapshot()`保证了查询将返回每个文档不会多于一次。

警告

  • 方法:method:`~cursor.snapshot()`不会保证查询返回的数据能够反映最新的单个文档同时也*不会*提供阻止插入和删除的操作。

  • 您**不能**在:term:sharded collections <sharding>`中使用:method:`~cursor.snapshot()

  • 您**不能**与:method:`~cursor.sort()`或者:method:`~cursor.hint()`同时使用:method:`~cursor.snapshot()`方法。

作为替换方案,如果您的集合中有一个或者多个字段不会被更改,您可以在这个或者多个字段上使用*唯一性*索引来达到与:method:~cursor.snapshot()`相同的效果。查询的时候使用:method:`~cursor.hint() 声明强制走这个索引。

单体写

MongoDB在单节点:program:`mongod`实例、复制集和分片集群中都提供单体写的保证。

假设一个应用进行了一系列的操作包括了一个写操作*W*1`并在接下来进行了另外一个写操作*W*:sub:`2。MongoDB将保证*W*:sub:`1`操作在*W*:sub:`2`之前进行。

Real Time Order

3.4 新版功能.

For read and write operations on the primary, issuing read operations with "linearizable" read concern and write operations with "majority" write concern enables multiple threads to perform reads and writes on a single document as if a single thread performed these operations in real time; that is, the corresponding schedule for these reads and writes is considered linearizable.