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 SDK (
Microsoft.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.");
}
要么将这三个项目一起提交,要么一个都不要提交。 不存在部分状态。
在单个事务中混合操作类型
可以在同一事务中混合使用 CreateItem、UpsertItem、ReplaceItem、PatchItem 和 DeleteItem。
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 的支持。