原因是性能。不必在每次更改时写入磁盘,MongoDB 可以更快地处理更新。
MongoDB 会告诉您更新何时交付到服务器,而不是更新何时写入,您可以在Verifying Propagation of Writes with getLastError 上的文档中阅读:
注意:当数据已经传送到 [the] 服务器时,当前实现会返回。未来的版本将提供更多交付选项,而不是服务器上的物理 fsync。
这违背了ACID,更具体地说,违背了代表耐用性的D:
持久性 [保证]一旦通知用户事务成功,事务不会丢失,事务的数据更改将在系统故障后继续存在,并且所有完整性约束都已满足,因此 DBMS 不需要撤销交易。
ACID 属性主要适用于传统的 RDBMS 系统。包括 MongoDB 在内的 NoSQL 系统放弃了一种或多种 ACID 属性,以实现更好的可扩展性。在 MongoDB 的案例中,牺牲了耐用性,以便在处理大量更新时获得更好的性能。
MongoDB 和 ACID
大多数 ACID 属性是事务级别的保证。事务通常是一组查询,应被视为一个单元。 MongoDB 没有事务的概念,同样适用于performance reasons。因此大多数 ACID 属性不适用于 MongoDB。
A——原子性表明事务要么成功要么失败。不允许部分成功;如果部分事务失败,则应回滚整个事务。 MongoDB 在文档级别支持atomic operations,但不支持“事务”级别。
C——一致性部分指的是原子性,但也包括参照完整性。关系数据库负责确保所有外键引用都是有效的。 MongoDB 没有外键的概念,所以这个 ACID 属性不适用。
I — 隔离声明不允许两个并发事务相互干扰;如果两个事务尝试修改相同的数据,则第二个事务必须等待第一个事务完成。为此,数据库将锁定数据。 MongoDB 没有锁定的概念,因此不支持多个操作的隔离1)。单个操作是隔离的。
D — 上面描述了耐用性。就 ACID-ic 持久性而言,MongoDB 不支持真正的持久性。
现在,您可能认为 MongoDB 与 RDBMS 系统相比毫无用处,因为它缺乏事务和大多数 ACID 保证。但是,事务存在的部分原因是关系数据库需要将某些数据视为单个实体,而这些数据已被规范化为多个表。
MongoDB 允许您将数据存储为单个实体。在大多数情况下,这消除了对外键和参照完整性的需求。您也不需要多查询事务,因为您不需要多个表来更新单个实体。大多数时候你只需要更新一个文档,而这些操作在 MongoDB 中是原子的。
1) 根据first comment on this page,db.eval() 为多个操作提供隔离。但是,根据the documentation,您通常希望避免使用db.eval()。