在 Azure Cosmos DB 中使用分布式事务

Important

Azure Cosmos DB中的分布式事务目前以公共预览版提供。 此预览版在没有服务级别协议(SLA)的情况下提供。 在正式发布之前,行为、限制和支持的方案可能会更改。

本文介绍如何在Azure Cosmos DB上为NoSQL帐户启用分布式事务,并通过 .NET SDK 使用这些事务提交跨同一帐户和区域中多个逻辑分区、容器和数据库的原子读写操作。

本文中的示例使用单个方案 --一个包含两个 banking 容器的数据库( accounts 按帐户 ID 分区)和 ledger (通过发布月份进行分区)-因此,读取和写入示例中会显示相同的项。

先决条件

在开始之前,请确保具备:

  • 活动的 Azure 订阅。 如果没有 试用版,请创建一个试用版
  • 用于 NoSQL 的 Azure Cosmos DB 帐户。 该帐户必须:
    • 使用 NoSQL (Core SQL) API。 预览版不支持 MongoDB、Cassandra、表和 Gremlin API。
    • 必须是预配吞吐量帐户(手动或自动缩放)。 预览版不支持无服务器帐户。
    • 公共Azure云区域中运行。
    • 单写入区域账户。 预览版不支持多区域写入帐户。
    • 未配置以下任何功能:
      • 客户管理的密钥 (CMK)
      • 按分区自动故障转移(PPAF)
      • 连续备份
      • 长期保留
      • 分区合并
      • 分层分区键 (HPK)
      • Fabric 原生数据库
  • NuGet 中最新版本的 Azure Cosmos DB .NET v3 SDKMicrosoft.Azure.Cosmos)。

为您的账户申请登记

分布式事务是公开预览功能。 通过 Azure 门户、Azure CLI或 PowerShell 的自助服务注册当前不可用。

若要请求注册,请提交 分布式事务加入表单。 请求通常在一到两个工作日内完成。 帐户准备就绪后会收到确认。

安装所需的.NET SDK

将Azure Cosmos DB .NET SDK 的最新预览版(v3.62.0-preview.0)添加到项目中。

dotnet add package Microsoft.Azure.Cosmos --version 3.62.0-preview.0

初始化客户端

使用 Microsoft Entra ID 或账户密钥,针对你已注册的账户初始化 CosmosClient

将 Microsoft Entra ID 用于生产环境。 若要使用所需的角色分配和凭据来设置帐户,请参阅使用基于角色的访问控制连接到 Azure Cosmos DB for NoSQL

using Microsoft.Azure.Cosmos;
using Azure.Identity;

string endpoint = "https://<your-account>.documents.azure.cn:443/";

CosmosClient client = new CosmosClient(
    endpoint,
    new DefaultAzureCredential());

所使用的标识必须在参与事务的每个容器上具有数据平面写入权限(例如 Cosmos DB 内置数据参与者 角色)。 在事务批处理中,会针对每项单独操作进行角色检查。

提交多分区写入事务

.NET v3 SDK 将 CreateDistributedWriteTransaction() API 添加到 CosmosClient。 为每个项串联一个操作,然后调用 CommitTransactionAsync,将整个批处理作为单个原子单元提交。

以下示例以原子方式将 100 个单位从 account-A 转移到 account-B,并在 ledger 容器中记录相应的条目。 这两个帐户位于容器的不同逻辑分区 accounts 中,账本条目位于单独的容器中。

// Starting state: account-A holds 1000, account-B holds 1000.
// This transaction debits 100 from account-A and credits 100 to account-B,
// and writes a matching ledger entry — all atomically.
var updatedAccountA = new { id = "account-A", pk = "account-A", balance = 900.00 };
var updatedAccountB = new { id = "account-B", pk = "account-B", balance = 1100.00 };
var ledgerEntry     = new { id = "txn-1001",  pk = "2026-06",   from = "account-A", to = "account-B", amount = 100.00 };

DistributedTransactionResponse response = await client
    .CreateDistributedWriteTransaction()
    .ReplaceItem("banking", "accounts", new PartitionKey("account-A"), updatedAccountA)
    .ReplaceItem("banking", "accounts", new PartitionKey("account-B"), updatedAccountB)
    .CreateItem ("banking", "ledger",   new PartitionKey("2026-06"),   ledgerEntry)
    .CommitTransactionAsync(CancellationToken.None);

if (response.IsSuccessStatusCode)
{
    Console.WriteLine("Transaction committed.");
}

要么将这三个项目一起提交,要么一个都不要提交。 不存在部分状态。

在单个事务中混合操作类型

可以在同一事务中混合使用 CreateItemUpsertItemReplaceItemPatchItemDeleteItem

await client
    .CreateDistributedWriteTransaction()
    .UpsertItem("banking", "accounts", new PartitionKey("account-A"), updatedAccountA)
    .UpsertItem("banking", "accounts", new PartitionKey("account-B"), updatedAccountB)
    .CreateItem("banking", "ledger",   new PartitionKey("2026-06"),   ledgerEntry)
    .CommitTransactionAsync(CancellationToken.None);

提交多分区读取事务

当您需要获取位于不同逻辑分区、容器或数据库中的项的时间点一致快照时,请使用 CreateDistributedReadTransaction()。 与发起多个彼此独立的 ReadItemAsync 调用不同,分布式读事务会返回所有项在某一单个已提交时刻的状态,因此读取方绝不会看到仅部分生效的写事务。

为每个项链接一个 ReadItem 调用,然后调用 CommitTransactionAsync 以提取快照:

DistributedReadTransaction txn = client.CreateDistributedReadTransaction();

txn.ReadItem("banking", "accounts", new PartitionKey("account-A"), "account-A")
   .ReadItem("banking", "accounts", new PartitionKey("account-B"), "account-B");

DistributedTransactionResponse response = await txn.CommitTransactionAsync();

何时使用分布式读取事务

当正确性取决于跨分区分布的项 的相互一致性 时,分布式读取事务最有用。 常见方案包括:

  • 跨帐户余额对帐。 读取多腿资金转账所涉及的每个账户余额,以确认借方和贷方之和为零,并避免出现这种风险:在某笔并发转账提交之前读取其中一腿,而在其提交之后读取另一腿。
  • 库存和订单验证。 在决定是否接受新订单之前,先一起读取库存项和相应的待定订单记录,因此可用数量和预留数量始终反映相同的即时。
  • 审计与合规快照。 获取相关记录的统一视图(例如订单、订单行项目和分别位于不同容器中的客户资料),用于报表、导出或监管举证。
  • 缓存或读取模型重新生成。 从多个源容器填充反规范化视图或物化投影,而不会读到正在进行中的分布式写入事务导致的不完整写入。

对于单项读取,或者对于不需要相互一致性的不相关项,请继续使用 ReadItemAsync - 延迟较低,并且消耗的请求单位更少。

多区域注意事项

在多区域账户中,分布式事务仅在写入区域内具有原子性。 预览版不支持多区域写入帐户 - 该帐户必须具有单个写入区域。

    • SDK 将所有事务读取和写入路由到帐户的 写入区域
  • 提交的数据 以异步方式和按分区复制到次要区域。 次要区域中的读取器可能会暂时观察部分更新,直到复制赶上。

对于需要对事务性数据进行全局写后读的应用程序,可采用以下任一方式:

  • 将读取路由到写入区域,或
  • 在账户级别使用 强一致性,以及提交响应返回的会话令牌。

公共预览版中的限制

Limit 价值
每个事务的最大操作数 100
每个事务的最大有效负载大小 2 MB

在正式发布之前,这些限制可能会更改。

支持的 API 和 SDK

目前,只有 NoSQL (Core SQL) API 支持分布式事务。

.NET v3 SDK 支持分布式事务。 即将推出对其他 SDK 的支持。