Azure存储表 - 插入批处理行并检查它们是否存在

时间:2016-11-18 17:37:41

标签: c# azure azure-storage azure-table-storage

我发送一些服务的查询并获取结果。我想知道我是否已经得到同样的答案"回答"在过去。所以,我计划使用Azure Table作为缓存机制。

我做了这个小POC:

TableBatchOperation batchOperation = new TableBatchOperation();
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1");
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2");
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
table.ExecuteBatch(batchOperation);

当我第一次运行此代码时,它运行正常。在这结束时,我在表中有2行。

问题出在第二轮。当我执行此代码时:

TableBatchOperation batchOperation = new TableBatchOperation();
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1");
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2");
CachedUrl customer3 = new CachedUrl(Guid.Empty, "test3");
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
batchOperation.Insert(customer3);
table.ExecuteBatch(batchOperation);

注意添加customer3

期望获得的消息是:

  • customer1 - 存在
  • customer2 - 存在
  • customer3 - 已添加

我实际获得的是此异常(在ExecuteBatch()方法上):

  

请求信息请求ID:5116ee8a-0002-0024-7ac1-415787000000   RequestDate:2016年11月18日星期五17:33:08 GMT StatusMessage:0:The   指定的实体已存在。错误码:EntityAlreadyExists

服务器发现#1实体存在,因此,跳过整个任务。

我如何得到预期的答案?

天真的解决方案是尝试逐个添加所有N个项目。但是这个解决方案是最慢的(N HTTP请求而不是1个请求)。

2 个答案:

答案 0 :(得分:2)

Azure表存储批处理操作是原子操作,因此预计会在第一次失败的操作时返回。批处理操作可能包含1000个操作,表服务在检测到第一个故障后继续执行所有操作没有多大意义。

存储异常返回批处理中失败操作的实际索引以及与之相关的错误。

在下面的示例中,失败操作的索引为0,错误为EntityAlreadyExists:

0 :指定的实体已存在。 ErrorCode:EntityAlreadyExists

您可以编写捕获StorageException的重试逻辑,解析错误,如果错误是EntityAlreadyExists,则从批处理中删除该索引的操作,然后重新提交批处理操作。

请参阅我在Nuget中实现的azure Storage Exception解析器,它为您提取StorageException对象中的失败操作的索引和其他有用的信息,如HttpStatusCode:https://www.nuget.org/packages/AzureStorageExceptionParser/

为了避免在每次失败的操作中多次来回调用azure,以下是您可以探索的替代解决方案:

每次向表中插入实体时,也会插入第二个实体,该实体具有相同的分区键,该键只包含一个行键属性。让我们调用第二个实体RowKeyTracker实体。它将与原始实体具有相同的分区键,以便您可以执行批处理操作。它将具有一个唯一的行键,您可以知道它以查询它,它将具有一个属性,该属性是该分区的附加行键。如果RowKeyTracker实体已存在,则只需在每次插入新实体时将新行键附加到其分区键的行键属性,反之亦然,当您删除实体时,您也可以继续从RowKeyTracker中删除该行键实体。

因此,您可以使用此行键跟踪器实体来确定是否已插入该分区的行键,方法是先查询它。

您可以将此方法与第一种方法(重试)结合使用,以获得更强大的解决方案

答案 1 :(得分:0)

这是预期的行为。只要该批次中的任何实体发生故障,整个批次就会失败。

您可以做的一件事是使用InsertOrReplace方法而不是Insert。这将更新实体(如果存在),否则插入实体。

来自documentation

  

将TableOperation添加到插入的TableBatchOperation中   如果实体不存在,则将指定实体放入表中;如果   实体确实存在,然后用提供的内容替换它的内容   实体。