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

适用范围:

警告

此项目处于其生命周期 的社区支持 阶段。 最终,所有关联的客户端库都将永久停用。 有关停用和使用此项目的替代方法的详细信息,请参阅 停用通知:Azure 存储 PHP 客户端库

提示

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

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

创建 Azure 服务帐户

可以通过 Azure 表存储或 Azure Cosmos DB 使用表。 若要详细了解这两个服务中的表产品/服务之间的差异,请参阅 适用于表的 API 概述。 需要为要使用的服务创建一个帐户。 以下部分说明了如何创建 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 中的类。 可以使用任何开发工具(包括“记事本”)创建应用程序。

在本指南中,你将使用可从 PHP 应用程序中调用的 Azure 表存储或 Azure Cosmos DB for Table 功能。 应用程序可以在本地运行,也可以在 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 帐户。 根据所使用的帐户类型获取连接字符串。

添加存储表服务连接

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

$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 />";
}

检索分区中的一部分实体

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

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 />";
}