OPTIONS
翻译或纠错本页面

隔离操作的序列

概述

在单文档级别上写操作是原子的:没有单个的写操作可以原子地影响不止一个文档或者集合。

当一个单独的写操作修改多个文档的时候,这一整个操作不是原子的,并且其他操作可能交错。一个单文档或者记录的修改总是原子的,即使写操作修改多个子文档 的单个记录。

没有其他的操作是原子的;然而,你可以使用 isolation operator隔离 一个影响多个文档的写操作。

这个文档描述了一种方法, 仅仅 当本地文档副本反映数据库中文档的当前状态时更新文档。另外,下面的方法提供了一个管理隔离操作序列的途径:

Update if Current

在这个模型下,你将:

  • 查询一个文档,

  • 修改在那个文档中的字段

  • 并且 仅仅当 集合中的字段自查询以来没有发生变化的时候更新这些字段。

思考下面的JavaScript例子,它尝试更新 products 集合里面的一个文档的 qty 字段:

在 2.6 版更改: 现在 db.collection.update() 方法返回一个包含操作状态的 WriteResult() 对象。以前的版本需要一个额外的 db.getLastErrorObj() 方法调用。

var myCollection = db.products;
var myDocument = myCollection.findOne( { sku: 'abc123' } );

if (myDocument) {

   var oldQty = myDocument.qty;

   if (myDocument.qty < 10) {
       myDocument.qty *= 4;
   } else if ( myDocument.qty < 20 ) {
       myDocument.qty *= 3;
   } else {
       myDocument.qty *= 2;
   }

   var results = myCollection.update(
      {
        _id: myDocument._id,
        qty: oldQty
      },
      {
        $set: { qty: myDocument.qty }
      }
   );

   if ( results.hasWriteError() ) {
       print("unexpected error updating document: " + tojson( results ));
   } else if ( results.nMatched == 0 ) {
       print("No update: no matching document for { _id: " + myDocument._id + ", qty: " + oldQty + " }")
   }

}

你的应用可能需要对这个模型进行一些修改,比如:

  • update() 操作里使用整个文档作为查询条件,以使这个操作更加通用( generalize the operation)并且保证原始的文档未被修改,而不仅仅是保证单个字段未改变。

  • 为这个文档添加一个版本变量,that applications increment upon each update operation to the documents. 在查询表达式中使用这个版本变量。你必须能够保证 所有 连接到你的数据库的客户端遵从这个约束。

  • 在更新表达式中使用 $set 来仅仅修改你的(要修改的)字段,并且预防覆盖其他字段。

  • 使用 创建一个自增的序列字段 中描述的方法中的一个。