如何通过 PHP 使用 Azure 存储表服务或 Azure Cosmos DB for Table

适用对象:

提示

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

本文介绍如何创建表、存储数据以及对数据执行 CRUD 操作。 选择 Azure 表服务或 Azure Cosmos DB for Table。 示例是采用 PHP 编写的,并使用了 Azure 存储表 PHP 客户端库。 涉及的方案包括创建和删除表以及在表中插入、删除和查询实体。 有关 Azure 表服务的详细信息,请参阅后续步骤部分。

创建 Azure 服务帐户

可以通过 Azure 表存储或 Azure Cosmos DB 使用表。 若要详细了解这两个服务中的表产品/服务之间的差异,请参阅 API for Table 概述。 需要为所要使用的服务创建一个帐户。 以下部分说明了如何创建 Azure 表存储和 Azure Cosmos DB 帐户,但你只需使用其中一个。

创建 Azure 存储帐户

创建 Azure 存储帐户的最简单方法是使用 Azure 门户。 若要了解更多信息,请参阅 创建存储帐户

也可以使用 Azure PowerShellAzure CLI 创建 Azure 存储帐户。

如果暂时不想创建存储帐户,也可以使用 Azure 存储模拟器在本地环境中运行和测试代码。 有关详细信息,请参阅使用 Azure 存储模拟器进行开发和测试

创建 Azure Cosmos DB for Table 帐户

有关创建 Azure Cosmos DB for Table 帐户的说明,请参阅创建数据库帐户

创建 PHP 应用程序

创建 PHP 应用程序来访问存储表服务或 Azure Cosmos DB for Table 的唯一要求是在代码中引用 PHP 的 azure-storage-table SDK 中的类。 可以使用任何开发工具(包括“记事本”)创建应用程序。

在本指南中,将使用存储表服务或 Azure Cosmos DB 功能,这些功能可在 PHP 应用程序中本地调用,或通过在 Azure 的 Web 角色、辅助角色或网站中运行的代码调用。

获取客户端库

  1. 在项目的根目录中创建一个名为 composer.json 的文件并向其添加以下代码:
    {
    "require": {
     "microsoft/azure-storage-table": "*"
    }
    }
    
  2. composer.phar 下载到根目录中。
  3. 打开命令提示符并在项目根目录中执行以下命令:
    php composer.phar install
    
    或者,转到 GitHub 上的 Azure 存储表 PHP 客户端库,然后克隆源代码。

添加所需引用

若要使用存储表服务或 Azure Cosmos DB API,必须:

  • 使用 require_once 语句引用 autoloader 文件,并
  • 引用所使用的所有类。

以下示例展示了如何添加 autoloader 文件并引用 TableRestProxy 类。

require_once 'vendor/autoload.php';
use MicrosoftAzure\Storage\Table\TableRestProxy;

在下面的示例中,require_once 语句将始终显示,但只会引用执行该示例所需的类。

添加连接字符串

可以连接到 Azure 存储帐户,也可以连接到 Azure Cosmos DB for Table 帐户。 根据所使用的帐户类型获取连接字符串。

添加存储表服务连接

若要实例化存储表服务客户端,必须首先具有有效的连接字符串。 表存储服务连接字符串的格式为:

$connectionString = "DefaultEndpointsProtocol=[http|https];AccountName=[yourAccount];AccountKey=[yourKey]"

添加存储模拟器连接

若要访问模拟器存储,请执行以下操作:

UseDevelopmentStorage = true

添加 Azure Cosmos DB 连接

若要实例化 Azure Cosmos DB 表客户端,必须首先具有有效的连接字符串。 Azure Cosmos DB 连接字符串的格式为:

$connectionString = "DefaultEndpointsProtocol=[https];AccountName=[myaccount];AccountKey=[myaccountkey];TableEndpoint=[https://myendpoint/]";

若要创建 Azure 表服务客户端或 Azure Cosmos DB 客户端,需要使用 TableRestProxy 类。 可以:

  • 将连接字符串直接传递给此类或
  • 使用 CloudConfigurationManager (CCM) 检查多个外部源以获取连接字符串:
    • 默认情况下,它附带了对一个外部源的支持 - 环境变量。
    • 可通过扩展 ConnectionStringSource 类来添加新源。

在此处列出的示例中,将直接传递连接字符串。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;

$tableClient = TableRestProxy::createTableService($connectionString);

创建表

利用 TableRestProxy 对象,可以使用 createTable 方法创建表。 创建表时,可以设置表服务超时。 (有关表服务超时的详细信息,请参阅为表服务操作设置超时。)

require_once 'vendor\autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

// Create Table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

try    {
    // Create table.
    $tableClient->createTable("mytable");
}
catch(ServiceException $e){
    $code = $e->getCode();
    $error_message = $e->getMessage();
    // Handle exception based on error codes and messages.
    // Error codes and messages can be found here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
}

有关表名称限制的信息,请参阅了解表服务数据模型

将实体添加到表

若要将实体添加到表,请创建新的 Entity 对象并将其传递到 TableRestProxy->insertEntity。 请注意,在创建实体时,必须指定 PartitionKeyRowKey。 这些值是实体的唯一标识符,并且其查询速度比其他实体属性的查询速度快得多。 系统使用 PartitionKey 自动将表的实体分发到许多存储节点上。 具有相同 PartitionKey 的实体存储在同一个节点上。 (对存储在同一节点上的多个实体执行操作要将比对存储在不同节点上的实体执行的操作的效果更佳。)RowKey 是实体在分区中的唯一 ID。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;
use MicrosoftAzure\Storage\Table\Models\Entity;
use MicrosoftAzure\Storage\Table\Models\EdmType;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

$entity = new Entity();
$entity->setPartitionKey("tasksSeattle");
$entity->setRowKey("1");
$entity->addProperty("Description", null, "Take out the trash.");
$entity->addProperty("DueDate",
                        EdmType::DATETIME,
                        new DateTime("2012-11-05T08:15:00-08:00"));
$entity->addProperty("Location", EdmType::STRING, "Home");

try{
    $tableClient->insertEntity("mytable", $entity);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
}

有关表属性和类型的信息,请参阅了解表服务数据模型

TableRestProxy 类提供了用于插入实体的两个替代方法:insertOrMergeEntityinsertOrReplaceEntity。 要使用这些方法,请创建新的 Entity,并将其作为参数传递到上述任一方法。 如果实体不存在,则每种方法都将插入实体。 在实体已存在的情况下,如果属性已存在,则 insertOrMergeEntity 更新属性值;如果属性不存在,则该方法添加新属性,而 insertOrReplaceEntity 会完全替换现有实体。 下面的示例演示如何使用 insertOrMergeEntity。 如果 PartitionKey 为“tasksSeattle”且 RowKey 为“1”的实体不存在,则将插入该实体。 但是,如果之前已插入该实体(如上面的示例所示),则将更新 DueDate 属性并添加 Status 属性。 系统还将更新 DescriptionLocation 属性,但使用的值实际上会使其保持不变。 如果后面两个属性不是如示例中所示添加的,但已存在于目标实体上,则其现有值将保持不变。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;
use MicrosoftAzure\Storage\Table\Models\Entity;
use MicrosoftAzure\Storage\Table\Models\EdmType;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

//Create new entity.
$entity = new Entity();

// PartitionKey and RowKey are required.
$entity->setPartitionKey("tasksSeattle");
$entity->setRowKey("1");

// If entity exists, existing properties are updated with new values and
// new properties are added. Missing properties are unchanged.
$entity->addProperty("Description", null, "Take out the trash.");
$entity->addProperty("DueDate", EdmType::DATETIME, new DateTime()); // Modified the DueDate field.
$entity->addProperty("Location", EdmType::STRING, "Home");
$entity->addProperty("Status", EdmType::STRING, "Complete"); // Added Status field.

try    {
    // Calling insertOrReplaceEntity, instead of insertOrMergeEntity as shown,
    // would simply replace the entity with PartitionKey "tasksSeattle" and RowKey "1".
    $tableClient->insertOrMergeEntity("mytable", $entity);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

检索单个实体

利用 TableRestProxy->getEntity 方法,可以通过查询实体的 PartitionKeyRowKey 来检索它。 在以下示例中,分区键 tasksSeattle 和行键 1 传递给 getEntity 方法。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

try    {
    $result = $tableClient->getEntity("mytable", "tasksSeattle", 1);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

$entity = $result->getEntity();

echo $entity->getPartitionKey().":".$entity->getRowKey();

检索分区中的所有实体

使用筛选器构造实体查询(有关详细信息,请参阅查询表和实体)。 若要检索分区中的所有实体,请使用筛选器“PartitionKey eq partition_name”。 下面的示例演示如何通过将筛选器传递到 queryEntities 方法来检索 tasksSeattle 分区中的所有实体。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

$filter = "PartitionKey eq 'tasksSeattle'";

try    {
    $result = $tableClient->queryEntities("mytable", $filter);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

$entities = $result->getEntities();

foreach($entities as $entity){
    echo $entity->getPartitionKey().":".$entity->getRowKey()."<br />";
}

检索分区中的一部分实体

可以使用上一示例中使用的同一模式来检索分区中的部分实体。 检索的实体子集由所使用的筛选器确定(有关详细信息,请参阅查询表和实体)。下面的示例演示如何使用筛选器检索具有特定 Location 和早于指定日期的 DueDate 的所有实体。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

$filter = "Location eq 'Office' and DueDate lt '2012-11-5'";

try    {
    $result = $tableClient->queryEntities("mytable", $filter);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

$entities = $result->getEntities();

foreach($entities as $entity){
    echo $entity->getPartitionKey().":".$entity->getRowKey()."<br />";
}

检索一部分实体属性

查询可检索一部分实体属性。 此方法称为投影,可减少带宽并提高查询性能,尤其适用于大型实体。 若要指定要检索的属性,请将该属性的名称传递到 Query->addSelectField 方法。 可以多次调用此方法来添加更多属性。 执行 TableRestProxy->queryEntities 后,返回的实体将仅具有选定的属性。 (若要返回一部分表实体,请使用上述查询中所示的筛选器。)

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;
use MicrosoftAzure\Storage\Table\Models\QueryEntitiesOptions;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

$options = new QueryEntitiesOptions();
$options->addSelectField("Description");

try    {
    $result = $tableClient->queryEntities("mytable", $options);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

// All entities in the table are returned, regardless of whether
// they have the Description field.
// To limit the results returned, use a filter.
$entities = $result->getEntities();

foreach($entities as $entity){
    $description = $entity->getProperty("Description")->getValue();
    echo $description."<br />";
}

更新实体

可通过对现有实体使用 Entity->setProperty 和 Entity->addProperty 方法并调用 TableRestProxy->updateEntity 来更新该实体。 下面的示例将检索一个实体、修改一个属性、删除另一个属性并添加一个新属性。 请注意,将属性值设为 null 可删除该属性。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;
use MicrosoftAzure\Storage\Table\Models\Entity;
use MicrosoftAzure\Storage\Table\Models\EdmType;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

$result = $tableClient->getEntity("mytable", "tasksSeattle", 1);

$entity = $result->getEntity();
$entity->setPropertyValue("DueDate", new DateTime()); //Modified DueDate.
$entity->setPropertyValue("Location", null); //Removed Location.
$entity->addProperty("Status", EdmType::STRING, "In progress"); //Added Status.

try    {
    $tableClient->updateEntity("mytable", $entity);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

删除实体

若要删除实体,请将表名称以及实体的 PartitionKeyRowKey 传递到 TableRestProxy->deleteEntity 方法。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

try    {
    // Delete entity.
    $tableClient->deleteEntity("mytable", "tasksSeattle", "2");
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

为了进行并发检查,可以使用 DeleteEntityOptions->setEtag 方法并将 DeleteEntityOptions 对象作为第四个参数传递到 deleteEntity,来为要删除的实体设置 Etag。

对表操作进行批处理

利用 TableRestProxy->batch 方法,可以通过一个请求执行多个操作。 此处的模式涉及将操作添加到 BatchRequest 对象,并将 BatchRequest 对象传递到 TableRestProxy->batch 方法。 要将操作添加到 BatchRequest 对象,可以多次调用以下任一方法:

  • addInsertEntity(添加 insertEntity 操作)
  • addUpdateEntity(添加 updateEntity 操作)
  • addMergeEntity(添加 mergeEntity 操作)
  • addInsertOrReplaceEntity(添加 insertOrReplaceEntity 操作)
  • addInsertOrMergeEntity(添加 insertOrMergeEntity 操作)
  • addDeleteEntity(添加 deleteEntity 操作)

下面的示例演示了如何通过单个请求执行 insertEntitydeleteEntity 操作。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;
use MicrosoftAzure\Storage\Table\Models\Entity;
use MicrosoftAzure\Storage\Table\Models\EdmType;
use MicrosoftAzure\Storage\Table\Models\BatchOperations;

// Configure a connection string for Storage Table service.
$connectionString = "DefaultEndpointsProtocol=[http|https];AccountName=[yourAccount];AccountKey=[yourKey]"

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

// Create list of batch operation.
$operations = new BatchOperations();

$entity1 = new Entity();
$entity1->setPartitionKey("tasksSeattle");
$entity1->setRowKey("2");
$entity1->addProperty("Description", null, "Clean roof gutters.");
$entity1->addProperty("DueDate",
                        EdmType::DATETIME,
                        new DateTime("2012-11-05T08:15:00-08:00"));
$entity1->addProperty("Location", EdmType::STRING, "Home");

// Add operation to list of batch operations.
$operations->addInsertEntity("mytable", $entity1);

// Add operation to list of batch operations.
$operations->addDeleteEntity("mytable", "tasksSeattle", "1");

try    {
    $tableClient->batch($operations);
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

有关对表操作进行批处理的详细信息,请参阅执行实体组事务

删除表

最后,若要删除表,请将表名传递到 TableRestProxy->deleteTable 方法。

require_once 'vendor/autoload.php';

use MicrosoftAzure\Storage\Table\TableRestProxy;
use MicrosoftAzure\Storage\Common\Exceptions\ServiceException;

// Create table REST proxy.
$tableClient = TableRestProxy::createTableService($connectionString);

try    {
    // Delete table.
    $tableClient->deleteTable("mytable");
}
catch(ServiceException $e){
    // Handle exception based on error codes and messages.
    // Error codes and messages are here:
    // https://learn.microsoft.com/rest/api/storageservices/Table-Service-Error-Codes
    $code = $e->getCode();
    $error_message = $e->getMessage();
    echo $code.": ".$error_message."<br />";
}

后续步骤

现在,你已了解了 Azure 表服务和 Azure Cosmos DB 的基础知识,请单击下面的链接来了解更多信息。