你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

如何将 Azure SDK for Go 与 Azure 表结合使用

适用对象:

提示

本文中的内容适用于 Azure 表存储和 Azure Cosmos DB for Table。 API for Table 是表存储的高级产品/服务,可提供吞吐量优化表、全局分发和自动辅助索引。

本文介绍如何使用 Azure SDK for Go 创建、列出和删除 Azure 表和表实体。

通过 Azure 表,可在云中存储结构化 NoSQL 数据,通过无架构设计提供键属性存储。 由于 Azure 表存储无架构,因此可以很容易地随着应用程序需求的发展使数据适应存储。 对于许多应用程序来说,访问表数据和 API 是一种快速且经济高效的解决方案。

可以使用表存储或 Azure Cosmos DB 来存储灵活的数据集,例如 Web 应用程序的用户数据、通讯簿、设备信息。 或者,存储服务需要的其他类型的元数据。 可以在表中存储任意数量的实体,并且一个存储帐户可以包含任意数量的表,直至达到存储帐户的容量极限。

在本文中了解如何使用 Azure SDK for Go 管理 Azure 表存储。

先决条件

设置环境

要继续学习本教程,需要一个 Azure 资源组、一个存储帐户和一个表资源。 运行以下命令来设置环境:

  1. 创建 Azure 资源组。

    az group create --name myResourceGroup --location eastus
    
  2. 接下来,为新的 Azure 表创建 Azure 存储帐户。

    az storage account create --name <storageAccountName> --resource-group myResourceGroup --location eastus --sku Standard_LRS
    
  3. 创建表资源。

    az storage table create --account-name <storageAccountName> --account-key 'storageKey' --name mytable
    

安装包

需要两个包才能使用 Go 管理 Azure 表:azidentityaztables。 通过此 azidentity 包可向 Azure 进行身份验证。 使用 aztables 包可管理 Azure 中的表资源。 运行以下 Go 命令来安装这些包:

go get github.com/Azure/azure-sdk-for-go/sdk/data/aztables
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity

若要详细了解如何向 Azure 进行身份验证,请参阅使用 Azure SDK for Go 进行 Azure 身份验证

创建示例应用程序

安装包后,创建一个使用 Azure SDK for Go 管理 Azure 表的示例应用程序。 运行 go mod 命令来创建一个名为 azTableSample 的新模块。

go mod init azTableSample

接下来,创建一个名为 main.go 的文件,然后将以下内容复制到其中:

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    "github.com/Azure/azure-sdk-for-go/sdk/data/aztables"
)

type InventoryEntity struct {
    aztables.Entity
    Price       float32
    Inventory   int32
    ProductName string
    OnSale      bool
}

type PurchasedEntity struct {
    aztables.Entity
    Price float32
    ProductName string
    OnSale bool
}

func getClient() *aztables.Client {
    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT environment variable not found")
    }

    tableName, ok := os.LookupEnv("AZURE_TABLE_NAME")
    if !ok {
        panic("AZURE_TABLE_NAME environment variable not found")
    }

    cred, err := azidentity.NewDefaultAzureCredential(nil)
    if err != nil {
        panic(err)
    }
    serviceURL := fmt.Sprintf("https://%s.table.core.windows.net/%s", accountName, tableName)
    client, err := aztables.NewClient(serviceURL, cred, nil)
    if err != nil {
        panic(err)
    }
    return client
}

func createTable(client *aztables.Client) {
    //TODO: Check access policy, Storage Blob Data Contributor role needed
    _, err := client.Create(context.TODO(), nil)
    if err != nil {
        panic(err)
    }
}

func addEntity(client *aztables.Client) {
    myEntity := InventoryEntity{
        Entity: aztables.Entity{
            PartitionKey: "pk001",
            RowKey:       "rk001",
        },
        Price:       3.99,
        Inventory:   20,
        ProductName: "Markers",
        OnSale:      false,
    }

    marshalled, err := json.Marshal(myEntity)
    if err != nil {
        panic(err)
    }

    _, err = client.AddEntity(context.TODO(), marshalled, nil) // TODO: Check access policy, need Storage Table Data Contributor role
    if err != nil {
        panic(err)
    }
}

func listEntities(client *aztables.Client) {
    listPager := client.List(nil)
    pageCount := 0
    for listPager.More() {
        response, err := listPager.NextPage(context.TODO())
        if err != nil {
            panic(err)
        }
        fmt.Printf("There are %d entities in page #%d\n", len(response.Entities), pageCount)
        pageCount += 1
    }
}

func queryEntity(client *aztables.Client) {
    filter := fmt.Sprintf("PartitionKey eq '%v' or RowKey eq '%v'", "pk001", "rk001")
    options := &aztables.ListEntitiesOptions{
        Filter: &filter,
        Select: to.StringPtr("RowKey,Price,Inventory,ProductName,OnSale"),
        Top:    to.Int32Ptr(15),
    }

    pager := client.List(options)
    for pager.More() {
        resp, err := pager.NextPage(context.Background())
        if err != nil {
            panic(err)
        }
        for _, entity := range resp.Entities {
            var myEntity PurchasedEntity 
            err = json.Unmarshal(entity, &myEntity)
            if err != nil {
                panic(err)
            }
            fmt.Println("Return custom type [PurchasedEntity]")
            fmt.Printf("Price: %v; ProductName: %v; OnSale: %v\n", myEntity.Price, myEntity.ProductName, myEntity.OnSale)
        }
    }
}

func deleteEntity(client *aztables.Client) {
    _, err := client.DeleteEntity(context.TODO(), "pk001", "rk001", nil)
    if err != nil {
        panic(err)
    }
}

func deleteTable(client *aztables.Client) {
    _, err := client.Delete(context.TODO(), nil)
    if err != nil {
        panic(err)
    }
}

func main() {

    fmt.Println("Authenticating...")
    client := getClient()

    fmt.Println("Creating a table...")
    createTable(client)

    fmt.Println("Adding an entity to the table...")
    addEntity(client)

    fmt.Println("Calculating all entities in the table...")
    listEntities(client)

    fmt.Println("Querying a specific entity...")
    queryEntity(client) 

    fmt.Println("Deleting an entity...")
    deleteEntity(client) 

    fmt.Println("Deleting a table...")
    deleteTable(client)
}

重要

确保进行身份验证所使用的帐户具有用于管理 Azure 存储帐户的适当访问策略。 要运行上述代码,帐户至少需要具有存储 Blob 数据参与者角色和存储表数据参与者角色。

代码示例

验证客户端

// Lookup environment variables
accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT")
if !ok {
  panic("AZURE_STORAGE_ACCOUNT environment variable not found")
}

tableName, ok := os.LookupEnv("AZURE_TABLE_NAME")
if !ok {
  panic("AZURE_TABLE_NAME environment variable not found")
}

// Create a credential
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
  panic(err)
}

// Create a table client
serviceURL := fmt.Sprintf("https://%s.table.core.windows.net/%s", accountName, tableName)
client, err := aztables.NewClient(serviceURL, cred, nil)
if err != nil {
  panic(err)
}

创建表

// Create a table and discard the response
_, err := client.Create(context.TODO(), nil)
if err != nil {
  panic(err)
}

创建实体

// Define the table entity as a custom type
type InventoryEntity struct {
    aztables.Entity
    Price       float32
    Inventory   int32
    ProductName string
    OnSale      bool
}

// Define the entity values
myEntity := InventoryEntity{
    Entity: aztables.Entity{
        PartitionKey: "pk001",
        RowKey:       "rk001",
    },
    Price:       3.99,
    Inventory:   20,
    ProductName: "Markers",
    OnSale:      false,
}

// Marshal the entity to JSON
marshalled, err := json.Marshal(myEntity)
if err != nil {
    panic(err)
}

// Add the entity to the table
_, err = client.AddEntity(context.TODO(), marshalled, nil) // needs Storage Table Data Contributor role
if err != nil {
    panic(err)
}

获取实体

// Define the new custom type
type PurchasedEntity struct {
    aztables.Entity
    Price       float32
    ProductName string
    OnSale      bool
}

// Define the query filter and options
filter := fmt.Sprintf("PartitionKey eq '%v' or RowKey eq '%v'", "pk001", "rk001")
options := &aztables.ListEntitiesOptions{
    Filter: &filter,
    Select: to.StringPtr("RowKey,Price,Inventory,ProductName,OnSale"),
    Top:    to.Int32Ptr(15),
}

// Query the table for the entity
pager := client.List(options)
for pager.More() {
    resp, err := pager.NextPage(context.Background())
    if err != nil {
        panic(err)
    }
    for _, entity := range resp.Entities {
        var myEntity PurchasedEntity
        err = json.Unmarshal(entity, &myEntity)
        if err != nil {
            panic(err)
        }
        fmt.Println("Return custom type [PurchasedEntity]")
        fmt.Printf("Price: %v; ProductName: %v; OnSale: %v\n", myEntity.Price, myEntity.ProductName, myEntity.OnSale)
    }
}

删除实体

_, err := client.DeleteEntity(context.TODO(), "pk001", "rk001", nil)
if err != nil {
  panic(err)
}

删除表

_, err := client.Delete(context.TODO(), nil)
if err != nil {
  panic(err)
}

运行代码

剩下的工作就是运行应用程序。 但在执行此操作之前,需要设置环境变量。 使用以下命令创建两个环境变量,并将其设置为适当的值:

export AZURE_STORAGE_ACCOUNT=<YourStorageAccountName> 
export AZURE_TABLE_NAME=<YourAzureTableName>

接下来,运行以下 go run 命令来运行应用:

go run main.go

清理资源

运行以下命令来删除资源组及其所有剩余资源:

az group delete --resource-group myResourceGroup

后续步骤

在本快速入门教程中,已了解如何创建 Azure Cosmos DB 帐户、使用数据资源管理器创建表和运行应用。 现在可以使用 API for Table 进行数据查询了。