对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

事务

在MongoDB中,对单个文档的操作具有原子性。由于您可以使用嵌入式文档和数组来捕获单个文档结构中数据之间的关系,而不是跨多个文档和集合进行规范化,因此对于许多实际使用案例来说,多文档事务并不是必需的。

对于需要对多个文档进行操作的原子性的情况, MongoDB支持事务。您可以跨多个操作、集合、数据库、文档和分片使用事务。

MongoDB支持ACID事务。事务根据配置的读关注和写关注(write concern)设置提供原子性、一致性、隔离性和持久性。

使用语言选择器设置以下示例的语言。

提示

For an example in mongosh, see mongosh Example.

对于需要对多个文档(在单个或多个集合中)原子性读取和写入的情况,MongoDB 支持分布式事务,包括副本集和分片集群上的事务。

分布式事务具有原子性:

  • 事务要么应用所有数据更改,要么回滚更改。

  • 在事务提交时,事务中所做的所有数据更改都会保存,并且在事务之外可见。

    在事务进行提交前,在事务中所做的数据更改在事务外不可见。

    不过,当事务写入多个分片时,并非所有外部读取操作都需等待已提交事务的结果在各个分片上可见。例如,如果事务已提交并且写入 1 在分片 A 上可见,但写入 2 在分片 B 上尚不可见,则读关注 "local" 处的外部读取可以在不看到写入 2 的情况下读取写入 1 的结果。

  • 当ACID 事务中止时,ACID 事务中所做的所有数据更改都将被丢弃,并且永远不可见。

重要

在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。

有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项

事务可用于多个操作、集合、数据库、文档和分片。

对于事务:

  • 可以在事务中创建集合和索引。有关详细信息,请参阅在事务中创建集合和索引

  • 事务中使用的集合可以位于不同的数据库中。

    注意

    您无法在跨分片写事务中创建新集合。例如,如果您在一个分片中写入一个现有集合,并在另一个分片中隐式创建一个集合,MongoDB 将无法在同一事务中执行这两个操作。

  • 不能写入固定大小集合。

  • 固定大小集合读取时不能使用读关注 "snapshot"。(从 MongoDB 5.0 开始)

  • 不能在 configadminlocal 数据库中读取/写入集合。

  • 不能写入 system.* 集合。

  • 不能使用 explain 或类似命令返回受支持操作的查询计划。

  • 对于在 ACID 事务外部创建的游标,无法在 ACID 事务内部调用 getMore

  • 对于在事务中创建的游标,无法在事务外部调用 getMore

  • You cannot specify the killCursors command as the first operation in a transaction. Additionally, if you run the killCursors command within a transaction, the server immediately stops the specified cursors. It does not wait for the transaction to commit.

有关事务中不支持的操作列表,请参阅限制操作。

提示

在启动事务之前创建或删除集合时,如果在事务内部访问该集合,请发出带有写关注 "majority" 的创建或删除操作,以确保事务可以获取所需的锁。

如果不是跨分片写事务(write transaction),则可以在ACID 事务中执行以下操作:

  • 创建集合。

  • 在先前同一事务中创建的新空集合上创建索引。

在事务中创建集合时:

在事务内创建索引 [1] 时,要创建的索引必须位于以下位置之一:

  • 不存在的集合。集合作为操作的一部分创建。

  • 先前在同一事务中创建的新空集合。

[1] 您还可以对现有索引运行 db.collection.createIndex()db.collection.createIndexes() 以检查其是否存在。这些操作成功返回而不创建索引。
  • 您无法在跨分片写事务中创建新集合。例如,如果您在一个分片中写入一个现有集合,并在另一个分片中隐式创建一个集合,MongoDB 将无法在同一事务中执行这两个操作。

  • 当以分片集合为目标时,您无法在事务中使用 $graphLookup 阶段。

  • 要在事务内显式创建集合或索引,事务读关注级别必须为 "local"

    要显式创建集合和索引,请使用以下命令和方法:

要在事务内执行计数操作,请使用 $count 聚合阶段或 $group(带有 $sum 表达式)聚合阶段。

MongoDB 驱动程序提供集合级 API countDocuments(filter, options) 作为辅助方法,该方法使用 $group$sum 表达式来执行计数。

mongosh provides the db.collection.countDocuments() helper method that uses the $group with a $sum expression to perform a count.

如要在事务中执行不同的操作:

  • 对于未分片的集合,可以使用 db.collection.distinct() 方法/distinct 命令以及带有 $group 阶段的聚合管道。

  • 对于分片集合,不能使用 db.collection.distinct() 方法或 distinct 命令。

    要查找分片集合的不同值,请改用带有 $group 阶段的 aggregation pipeline。例如:

    • 不使用 db.coll.distinct("x"),而是使用

      db.coll.aggregate([
      { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
      { $project: { _id: 0 } }
      ])
    • 不使用 db.coll.distinct("x", { status: "A" }),而是使用

      db.coll.aggregate([
      { $match: { status: "A" } },
      { $group: { _id: null, distinctValues: { $addToSet: "$x" } } },
      { $project: { _id: 0 } }
      ])

    管道返回一个指向文档的游标:

    { "distinctValues" : [ 2, 3, 1 ] }

    迭代游标以访问结果文档。

事务中允许使用诸如 hellobuildInfoconnectionStatus(及其辅助方法)之类的信息命令,但它们不能是事务中的第一项操作。

事务中不允许执行以下操作:

  • 事务与会话关联。

  • 一个会话一次最多可以具有一个未结事务。

  • 使用驱动程序时,事务中的每项操作都必须与会话关联。有关详细信息,请参阅驱动程序特定文档。

  • 如果会话结束并且具有打开的事务,则事务将中止。

事务中的操作使用事务级读取偏好

使用驱动程序,您可以在事务启动时设置事务级读取偏好

  • 如果未设置事务级别的读取偏好,则事务将使用会话级别的读取偏好。

  • 如果未设置事务级别和会话级别的读取偏好,则事务将使用客户端级别的读取偏好。默认情况下,客户端级别的读取偏好为 primary

Transactions that contain read operations must use read preference primary. All operations in a given transaction must route to the same member.

事务中的操作使用事务级读关注。也就是说,在集合和数据库级别设置的任何读关注在事务中都会被忽略。

您可以在事务启动时设置事务级别的读关注

  • 如果未设置事务级别的读关注,则事务级别的读关注默认为会话级别的读关注。

  • 如果未设置事务级读关注和会话级读关注,则事务级读关注默认为客户端级读关注。默认情况下,对于主节点上的读取,客户端级读关注是 "local"。另请参阅:

事务支持以下读关注级别:

  • 读关注 "local" 返回节点中可用的最新数据,但可以回滚。

  • 在副本集上,即使ACID 事务使用读关注(read concern)local ,您也可能会观察到更强的读隔离性性,因为该操作会从ACID 事务打开点的快照中读取。

  • For transactions on sharded cluster, "local" read concern cannot guarantee that the data is from the same snapshot view across the shards. If snapshot isolation is required, use "snapshot" read concern.

  • You can create collections and indexes inside a transaction. If explicitly creating a collection or an index, the transaction must use read concern "local". If you implicitly create a collection, you can use any of the read concerns available for transactions.

  • If the transaction commits with write concern "majority", read concern "majority" returns data that has been acknowledged by a majority of the replica set members and can't be rolled back. Otherwise, read concern "majority" provides no guarantees that read operations read majority-committed data.

  • For transactions on sharded cluster, read concern "majority" can't guarantee that the data is from the same snapshot view across the shards. If snapshot isolation is required, use read concern "snapshot".

  • Read concern "snapshot" returns data from a snapshot of majority committed data if the transaction commits with write concern "majority".

  • If the transaction does not use write concern "majority" for the commit, the "snapshot" read concern provides no guarantee that read operations used a snapshot of majority-committed data.

  • 对于分片集群上的事务,数据的 "snapshot" 视图在各分片之间同步。

事务使用事务级写关注(write concern)来提交写入操作。事务内的写入操作必须在没有显式写关注(write concern)规范的情况下运行,并使用默认的写关注(write concern)。在提交时,使用事务级写关注(write concern)提交写入。

提示

请勿为事务中的各个写入操作显式设置写关注。为事务内的各个写入操作设置写关注会返回错误消息。

您可以在事务启动时设置事务级写关注

  • 如果未设置事务级别的写关注,则事务级别的写关注默认为提交的会话级别写关注。

  • 如果未设置事务级别的写关注和会话级别的的写关注,则事务级别的写关注默认为 的客户端级别的写关注,

事务支持所有写关注 w 值,包括:

  • 写关注 w: 1 会在提交应用于主节点后返回确认信息。

    重要

    使用 w: 1 提交时,如果发生故障转移,则可以回滚事务。

  • 使用w: 1写入关注提交时,事务级 "majority" 读关注无法保证事务中的读操作会读取大多数已提交数据。

  • 使用 w: 1 写关注提交时,事务级 "snapshot" 读关注无法保证事务中的读操作会使用大多数已提交数据的快照。

  • 在将提交应用于大多数投票节点后,写关注 w: "majority" 会返回确认消息。

  • 使用 w: "majority" 写关注提交时,事务级 "majority" 读关注可以保证操作已读取大多数已提交数据。对于分片集群上的事务,大多数已提交数据的视图不会在各分片之间同步。

  • 使用 w: "majority" 写关注提交时,事务级 "snapshot" 读关注可以保证操作已从大多数已提交数据的同步快照中读取。

注意

Regardless of the write concern specified for the transaction, the commit operation for a sharded cluster transaction includes some parts that use {w: "majority", j: true} write concern.

服务器参数 coordinateCommitReturnImmediatelyAfterPersistingDecision 可控制何时将事务提交决策返回给客户端。

该参数是在 MongDB 5.0 中引入的,默认值为 true。。在 MongoDB 6.1 中,该默认值更改为 false

coordinateCommitReturnImmediatelyAfterPersistingDecisionfalse 时,分片事务协调器会等待所有成员确认事务提交,然后再将提交决策返回给客户端。

如果您为写入指定"majority"写关注(write concern),并且该操作在返回响应之前没有复制到计算出的多数副本集成员,则数据最终会复制或回滚。请参阅wtimeout

Regardless of the write concern specified for the transaction, the driver applies w: "majority" as the write concern when retrying commitTransaction.

以下部分描述了因部署类型、存储引擎和MongoDB版本而异的ACID 事务要求和注意事项。

有关生产环境中的事务,请参阅生产环境注意事项。此外,有关分片集群,请参阅生产环境注意事项(分片集群)

Since arbiters are voting replicas that don't contain data, MongoDB protects your data and prevents multi-shard data transactions from targeting shards whose replica sets include an arbiter. This includes changing a shard key using a transaction.

如果任何ACID 事务操作读取或写入包含仲裁节点的分片,MongoDB会阻止写入操作跨越多个分片的事务。

To run transactions on a sharded cluster, writeConcernMajorityJournalDefault must be set to true.

注意

Regardless of the write concern specified for the transaction, the commit operation for a sharded cluster transaction includes some parts that use {w: "majority", j: true} write concern.

要获取事务状态和指标,请使用以下方法:

返回:

返回事务指标。

MongoDB Atlas免费集群或 Flex 集群不会返回某些 serverStatus 响应字段。有关更多信息,请参阅MongoDB Atlas文档中的有限命令

$currentOp 聚合管道

返回:

返回:

mongodmongos 日志消息

TXN 日志组件中包含有关慢速事务(即超过 operationProfiling.slowOpThresholdMs 阈值的事务)的信息。

要使用事务,所有部署节点的 featureCompatibilityVersion 必须至少为:

部署
最低 featureCompatibilityVersion

副本集(Replica Set)

4.0

分片集群

4.2

要检查成员的 FCV,请连接到该成员并运行以下命令:

db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

更多信息,请参阅 setFeatureCompatibilityVersion 参考页。

事务 在以下情况下,副本集和分片的集群支持:

  • 主节点使用 WiredTiger 存储引擎,而

  • 从节点使用 WiredTiger 存储引擎或内存存储引擎。

注意

您无法在具有将 writeConcernMajorityJournalDefault 设置为 false 的分片(例如具有使用内存中存储引擎的投票成员的分片)的分片集群上运行事务。

从 MongoDB 5.2(和 5.0.4)开始:

  • 当查询访问分片时,数据段迁移DDL 操作可能会占用集合的关键部分。

  • 要限制分片在事务中等待关键部分的时间,使用 metadataRefreshInTransactionMaxWaitMS 参数。

    注意

    从MongoDB 8.1 开始,旧的 metadataRefreshInTransactionMaxWaitBehindCritSecMS 参数已重命名为 metadataRefreshInTransactionMaxWaitMS。您可以继续使用 metadataRefreshInTransactionMaxWaitBehindCritSecMS 作为参数名称,但它已弃用,并将在未来的MongoDB发布中删除。