You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Table Storage 如何使用C#实现原子化获取或插入操作

实现Azure Table Storage原子化查询或创建操作(保留首次写入值)

核心实现思路

利用Azure Table Storage服务端原生的主键唯一性约束实现原子性,不需要额外引入分布式锁:

  • 同一个分区键(PartitionKey)+行键(RowKey)的实体,Insert操作仅允许第一次请求执行成功,后续同主键的Insert请求会被服务端直接拒绝,返回409冲突状态码
  • 无需提前查询实体是否存在,直接提交插入请求,插入成功则返回新实体,插入冲突则查询返回已存在的实体即可,完全避免竞态条件
  • 所有并发请求最终拿到的都是首次插入的实体,不会出现覆盖写入,也不会生成重复实体

代码示例(C# + Microsoft.Azure.Cosmos.Table 1.0.8)

using Microsoft.Azure.Cosmos.Table;
using System;
using System.Net;
using System.Threading.Tasks;

public class TableStorageService
{
    private readonly CloudTable _cloudTable;

    public TableStorageService(string storageConnectionString, string tableName)
    {
        var storageAccount = CloudStorageAccount.Parse(storageConnectionString);
        var tableClient = storageAccount.CreateCloudTableClient();
        _cloudTable = tableClient.GetTableReference(tableName);
        _cloudTable.CreateIfNotExists();
    }

    /// <summary>
    /// 原子化查询或创建实体,保留首次写入的值
    /// </summary>
    /// <typeparam name="T">实体类型,继承自TableEntity</typeparam>
    /// <param name="partitionKey">分区键</param>
    /// <param name="rowKey">行键</param>
    /// <param name="createEntityFactory">实体不存在时的构造委托,所有调用方生成的默认值需保持一致</param>
    /// <returns>已存在或新创建的实体</returns>
    /// <exception cref="ArgumentNullException"></exception>
    public async Task<T> GetOrCreateEntityAsync<T>(string partitionKey, string rowKey, Func<T> createEntityFactory) where T : TableEntity, new()
    {
        if (createEntityFactory == null)
            throw new ArgumentNullException(nameof(createEntityFactory));

        // 构造待插入的实体
        T newEntity = createEntityFactory();
        newEntity.PartitionKey = partitionKey;
        newEntity.RowKey = rowKey;

        try
        {
            // 直接执行插入操作,依赖服务端原子性校验
            var insertOperation = TableOperation.Insert(newEntity);
            var result = await _cloudTable.ExecuteAsync(insertOperation);
            return (T)result.Result;
        }
        catch (StorageException ex) when (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict)
        {
            // 捕获409冲突,说明实体已被其他请求插入,查询返回已有实体
            var retrieveOperation = TableOperation.Retrieve<T>(partitionKey, rowKey);
            var retrieveResult = await _cloudTable.ExecuteAsync(retrieveOperation);
            return (T)retrieveResult.Result;
        }
    }
}

// 自定义实体示例
public class MyBusinessEntity : TableEntity
{
    public string BusinessField1 { get; set; }
    public int BusinessField2 { get; set; }
}

// 调用示例
// var service = new TableStorageService("你的存储账户连接字符串", "你的表名");
// var entity = await service.GetOrCreateEntityAsync<MyBusinessEntity>("test_partition", "test_row", () => new MyBusinessEntity
// {
//     BusinessField1 = "默认值",
//     BusinessField2 = 0
// });

注意事项

  • 不要提前做查询判断:提前查询会引入额外的竞态窗口,直接提交插入请求是性能和原子性最优的方案
  • 异常捕获要精准:仅捕获409状态码的存储异常,其他异常(网络错误、权限错误等)需正常抛出,不要吞异常
  • 实体默认值要全局一致:所有并发请求的实体构造逻辑生成的默认值必须相同,才能保证不同请求的返回结果完全一致

内容的提问来源于stack exchange,提问作者Claus Appel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 04:12:07