Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob、Queue、File 和 Table。其中的 Table 就是本文的主角 Azure Table storage。

Azure Table storage 是一个在云端存储结构化 NoSQL 数据的服务。它不仅存取速度快,而且效费比高。MSDN 上的说法是:成本显著低于传统 SQL!
笔者最近在项目中用 Table storage 实现了一个日志表,在此和大家分享一下 Table storage 的基本用法。

Azure storage account

就概念上来讲,Table storage 只是 Azure 提供的存储服务的一种。其他的存储服务还有 Blob、Queue、File 等。对这些存储服务的访问控制都是通过 storage account 来进行的。所以要想使用 Table storage 需要先创建你的 storage account。具体创建过程不是本文重点,请参考 MSDN。但你需要去了解一下 Access keys,它就是你访问 storage account 的用户名和密码:

创建 Table storage 的对象

在使用 Azure Table storage 的相关对象前,我们需要安装对应的包。其实很简单,只需在 Visual Studio 的 Package Manager Console 中输入:

  1. Install-Package WindowsAzure.Storage

Visual Studio 会自动安装 WindowsAzure.Storage 包及其依赖的所有包,安装完成后的 packages.config 文件看起来像这个样子:

安装完相关的包以后,我们就可以使用其中的类型了。

CloudStorageAccount 类表示一个 Azure storage account,我们得先创建它的实例才能访问属于它的资源。

  1. // 注意连接字符串中的 xxx 和 yyy,分别对应 Access keys 中的 Storage account name 和 key。
  2. CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=yyy");
  3.  
  4. // CloudTableClient 类是 Windows Azure Table Service 客户端的逻辑表示。我们使用它来配置和执行对 Table storage 的操作。
  5. CloudTableClient cloudTableClient = storageAccount.CreateCloudTableClient();

CloudTable 类表示一张数据表。

  1. // 创建一个实例去引用 Table storage 中的一张表,我们测试用的表名叫 "MyLogTable"。
  2. CloudTable logTable = cloudTableClient.GetTableReference("MyLogTable");
  3. // 如果不确定表是否被创建过,可以调用 CreateIfNotExists 方法。
  4. logTable.CreateIfNotExists();

这样在后面的操作中就可以确保 MyLogTable 表是存在的。

有了 logTable 对象我们就可以向表中插入数据了。但是等等,好像少了点什么。我们开篇第一句中就说明了,Table storage 存储的是结构化的数据,所以我们还要先定义存储的数据的类型。

定义日志类

在定义我们自己的数据类型时,有一个强制性的要求,必须继承自 TableEntity 类型:

  1. internal class MyLogEntity : TableEntity
  2. {
  3. public MyLogEntity() { }
  4. public MyLogEntity(string pkey, string rkey)
  5. {
  6. this.PartitionKey = pkey;
  7. this.RowKey = rkey;
  8. }
  9.  
  10. public DateTime LogDate { get; set; }
  11. public string LogMessage { get; set; }
  12. public string ErrorType { get; set; }
  13. }

在我们的设计中,PartitionKey 用来存放产生日志的年份和月份(例如201607),RowKey 用来存放产生日志的天和时分秒毫秒(例如160934248492)。日志数据主要是 LogDate,LogMessage 和 ErrorType。

把数据插入到 Table storage

终于可以向表中插入数据了,试一下先:

  1. DateTime now = DateTime.Now;
  2. string partitionKey = now.ToString("yyyyMM");
  3. string rowKey = now.ToString("ddHHmmssffff");
  4. MyLogEntity logEntity = new MyLogEntity(partitionKey, rowKey);
  5. logEntity.LogDate = now;
  6. logEntity.LogMessage = "test message";
  7. logEntity.ErrorType = "error";
  8. // TableOperation 类表示对一个表进行的操作,可以插入一行或多行数据,删除数据,更新数据等。
  9. TableOperation insertOperation = TableOperation.Insert(logEntity);
  10. logTable.Execute(insertOperation);

看起来还不错,我们用 Visual Studio 自带的 Cloud Explorer 查看一下 MyLogTable 中的内容:

OK,数据已经成功插入到 MyLogTable 表中。接下来我们看看如何批量的插入数据。

  1. TableBatchOperation batchOperation = new TableBatchOperation();
  2. for (int i = ; i < ; i++)
  3. {
  4. DateTime now = DateTime.Now;
  5. string partitionKey = now.ToString("yyyyMM");
  6. string rowKey = now.ToString("ddHHmmssffff");
  7. MyLogEntity logEntity = new MyLogEntity(partitionKey, rowKey);
  8. logEntity.LogDate = now;
  9. logEntity.LogMessage = "test message" + i.ToString();
  10. logEntity.ErrorType = (i%) == ? "error" : "warning";
  11. batchOperation.Insert(logEntity);
  12. Thread.Sleep();
  13. }
  14. logTable.ExecuteBatch(batchOperation);

这次我们把 TableOperation 类换成了 TableBatchOperation 类,然后一次插入十条数据。去检查一下结果,OK 十条数据全部插入成功!
下面让我们把循环中的 10 改成 200 试试:

怎么收到一个 InvalidOperationException 呢?看看红框中的内容,原来批量操作是有一些限制的:
1.    每个批量操作的数据上限是 100 条记录。
2.    每个批量操作中的数据都必须保持相同的 partition key。
请大家在使用批量操作时务必注意这些限制条件!

查询操作

对于日志数据的操作,最重要的就是查询。我们通过几个具体的用例来介绍 Table storage 的查询操作。

查询所有的记录

这是最简单的查询方法,一般是想要导出全部数据时才会这么干:

  1. TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>();
  2. foreach (MyLogEntity entity in logTable.ExecuteQuery(query))
  3. {
  4. Console.WriteLine("{0}\t{1}\t{2}\t{3}", entity.PartitionKey, entity.RowKey, entity.LogMessage, entity.ErrorType);
  5. }

查询某年的某个月的记录

要查询某个月的所有记录也是比较容易的,因为我们设计的 PartitionKey 就代表了某个月份:

  1. TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>().Where(
  2. TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, ""));
  3. foreach (MyLogEntity entity in logTable.ExecuteQuery(query))
  4. {
  5. //...
  6. }

请注意 TableQuery.GenerateFilterCondition 方法,我们创建了一个过滤条件:PartitionKey 等于 "201607"。这个查询会把所有 PartitionKey 为 "201607" 的记录都找到!

查询某一条记录

如果我们已经知道了一条记录的 PartitionKey 和 RowKey,就可以通过这两个条件直接查询到这条记录的详情:

  1. TableQuery<MyLogEntity> query = new TableQuery<MyLogEntity>().Where(
  2. TableQuery.CombineFilters(
  3. TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, ""),
  4. TableOperators.And,
  5. TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.Equal, "")));
  6. foreach (MyLogEntity entity in logTable.ExecuteQuery(query))
  7. {
  8. //...
  9. }

这次我们使用了组合条件。虽然这里只使用了条件运算操作 TableOperators.And 和 QueryComparisons.Equal,你完全可以尝试其它的条件类型。唯一要注意的是:对于 PartitionKey 和 RowKey,QueryComparisons 的操作对象都是字符串。

我们还需要更多的查询条件,比如查询某一天产生的所有日志。在 MyLogTable 表中,这需要查询以 "xx" 字符串开头的 RowKey。我会单独在一篇文章中和大家分享相关内容,因为它并不像看起来的那么简单。
接下来我们介绍如何更新和删除日志表中的数据,当然这么做并不恰当,我们这里只是借用日志表介绍更新和删除操作而已。

更新记录

  1. TableOperation retrieveOperation = TableOperation.Retrieve<MyLogEntity>("", "");
  2. TableResult retrievedResult = logTable.Execute(retrieveOperation);
  3. MyLogEntity updateEntity = (MyLogEntity)retrievedResult.Result;
  4.  
  5. if (updateEntity != null)
  6. {
  7. updateEntity.LogMessage = "new log message";
  8. TableOperation updateOperation = TableOperation.Replace(updateEntity);
  9. logTable.Execute(updateOperation);
  10. }

这次我们先用 TableOperation.Retrieve 方法获得一条数据的详情,然后更新它的 LogMessage 属性,最后使用 TableOperation.Replace 方法把新的内容更新的到 Table storage 中。

删除记录

实际上删除一条记录和更新一条记录一样麻烦,不同点是把 TableOperation.Replace 方法换成 TableOperation.Delete 方法:

  1. TableOperation retrieveOperation = TableOperation.Retrieve<MyLogEntity>("", "");
  2. TableResult retrievedResult = logTable.Execute(retrieveOperation);
  3. MyLogEntity deleteEntity = (MyLogEntity)retrievedResult.Result;
  4. if (deleteEntity != null)
  5. {
  6. TableOperation deleteOperation = TableOperation.Delete(deleteEntity);
  7. logTable.Execute(deleteOperation);
  8. }

删除表

删除表和创建表一样简单(可比删除一条记录容易多了):

  1. logTable.DeleteIfExists();

总结

本文通过对一个日志表的操作介绍了 Azure Table storage 的一个典型应用场景和基本的使用方法。从操作的代码上看和传统的 sql 表操作差别还是挺大的。希望对朋友们了解 Azure Table storage 能有所帮助。

Azure 基础:Table storage的更多相关文章

  1. Azure 基础:自定义 Table storage 查询条件

    本文是在 <Azure 基础:Table storage> 一文的基础上介绍如何自定义 Azure Table storage 的查询过滤条件.如果您还不太清楚 Azure Table s ...

  2. 自定义 Azure Table storage 查询过滤条件

    本文是在Azure Table storage 基本用法一文的基础上,介绍如何自定义 Azure Table storage 的查询过滤条件.如果您还不太清楚 Azure Table storage ...

  3. Windows Azure Table storage 之 动态Table类 DynamicTableEntity

    在一般情况下,当我们在.net中使用Azure table storage的时候都会为该表建立一个TableEntity的派生类,如下所示. public class CustomerEntity : ...

  4. Azure 基础:Blob Storage

    Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob.Queue.File 和 Table. 笔者在前文中介绍了 Table Storage 的基本 ...

  5. Azure Storage 系列(四)在.Net 上使用Table Storage

    一,引言 今天我们就不多说废话了,直接进入正题,Azure Table Storage.开始内容之前,我们先介绍一下Azure Table Storage. 1,什么是Azure Table Stor ...

  6. Azure Table storage 基本用法 -- Azure Storage 之 Table

    Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob.Queue.File 和 Table,其中的 Table 就是本文的主角 Azure Tabl ...

  7. Azure Table storage 之改进DynamicTableEntity类为其添加动态语言扩展

    在之前的一篇文章中提到,storage类库中包含一个可以用来动态获取Azure table storage 表结构的类-DynamicTableEntity. 我们可以通过这个类,我们无需为每一个表提 ...

  8. Windows Azure入门教学系列 (六):使用Table Storage

    本文是Windows Azure入门教学的第六篇文章. 本文将会介绍如何使用Table Storage.Table Storage提供给我们一个云端的表格结构.我们可以把他想象为XML文件或者是一个轻 ...

  9. Windows Azure Table Storage 解决 Guid 查询问题

    在使用 Windows Azure Table Storage 的 CloudTableClient 对Azure 进行数据查询时,会发现在自定义类的Guid类型始终无法去成功查询出数据,对比发现 G ...

随机推荐

  1. aProxy: 带认证授权和权限控制的反向代理

    前段时间很多数据库因为没有做好权限控制暴露在外网被删然后遭勒索的事件,而类似的有些内网的web服务也会被开放到公网并且没有做任何权限控制的,这样也会有一定的风险.所以就决定写篇文章简单介绍一个小工具. ...

  2. java 解析xml文档---通过XmlPullParser解析方式

    package com.zx; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayLi ...

  3. html字体问题

    正如咱们在上一章中解说的那样,HTML元素使页面规划者能够对文档的构造进行符号.HTML标准列出了浏览器应该怎么显现这些元素的攻略.例如,您能够合理地保证强元素的内容将显现粗体.此外,您能够非常信赖大 ...

  4. 简谈-如何使用Python和R组合完成任务

    概述 和那些数据科学比赛不同,在真实的数据科学中,我们可能更多的时间不是在做算法的开发,而是对需求的定义和数据的治理.所以,如何更好的结合现实业务,让数据真正产生价值成了一个更有意义的话题. 数据科学 ...

  5. 人生苦短,我用Python

    Life is short, You need Python. 工作中常常要用到脚本来完成许多重复性的工作,刚开始是查数据库的时候,也曾用shell 来写脚本,但终于还是觉得shell太艰涩, 一行命 ...

  6. web安全—浏览器的进制

    浏览器的进制 字符的ascii码值可以转化为进制形式.可以用来绕过XSS filter. HTML属性值中的进制使用 .十进制使用a 表示,&#作为前缀,;作为后缀,后缀也可以没有. 如果要使 ...

  7. Ajaxfileupload 总结(包括插件处理json格式bug的解决方案)

    Ajaxfileupload 是一款轻量级js的上传插件,简单容易上手,今天简单学习了下. 1,引用jquery和Ajaxfileupload .js <script src="~/S ...

  8. JavaScript 复制对象

    在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...

  9. 学习笔记:JavaScript-进阶篇

    1.二维数组   二维数组的表示: myarray[ ][ ] var myarr=new Array();  //先声明一维 for(var i=0;i<2;i++){  //一维长度为2   ...

  10. [刷题]算法竞赛入门经典 3-12/UVa11809

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-4/UVa11809:Floating-Point Numbers 代码: //UVa11 ...