Как использовать клиентскую библиотеку таблиц Azure для Java

Область применения: Таблица

Совет

Содержимое этой статьи относится к хранилищу таблиц Azure и Azure Cosmos DB для таблицы. API для таблицы — это предложение уровня "Премиум" для хранилища таблиц, которое предлагает оптимизированные для пропускной способности таблицы, глобальное распределение и автоматические вторичные индексы.

В этой статье показано, как создавать таблицы, сохранять данные и выполнять операции CRUD с такими данными. Примеры написаны на Java, и в них используется клиентская библиотека таблиц Azure для Java. Рассматриваются сценарии создания, перечисления и удаления таблиц, а также вставки, запроса, изменения и удаления сущностей в таблице. Дополнительные сведения о таблицах см. в разделе Дальнейшие действия.

Внимание

Последняя версия клиентской библиотеки таблиц Azure, поддерживающей таблицу служба хранилища, а таблица Azure Cosmos DB — 12+.

Создание учетной записи службы Azure

Вы можете работать с таблицами, используя хранилище таблиц Azure или Azure Cosmos DB. Дополнительные сведения о различиях между предложениями таблиц в этих двух службах см. в обзоре API для таблиц. Для службы, которую вы планируете использовать, потребуется создать учетную запись. В следующих разделах показано, как создать и хранилище таблиц Azure, и учетную запись Azure Cosmos DB, однако можно использовать что-то одно.

Создание учетной записи службы хранилища Azure

Самый простой способ создать учетную запись хранения Azure — воспользоваться порталом Azure. Чтобы узнать больше, см. раздел Создание учетной записи хранилища.

Учетную запись хранения Azure можно создать также с помощью Azure PowerShell или Azure CLI.

Если вы не хотите сейчас создавать учетную запись хранения, код можно запустить и протестировать в локальной среде с помощью эмулятора хранения Azure. Дополнительные сведения см. в статье Использование Эмулятора службы хранилища Azure для разработки и тестирования.

Создание учетной записи Azure Cosmos DB

Инструкции по созданию учетной записи Azure Cosmos DB для таблицы см. в статье "Создание учетной записи базы данных".

Создание приложения Java

Для использования примеров из этой статьи сделайте следующее:

  1. Установите комплект SDK для Java (JDK).
  2. Создайте учетную запись хранения Azure или учетную запись Azure Cosmos DB в подписке Azure.
  3. Убедитесь, что ваша система разработки отвечает минимальным требованиям и зависимостям, указанным в репозитории клиентской библиотеки таблиц Azure для Java на сайте GitHub.
  4. Выполните инструкции по скачиванию и установке библиотек службы хранилища Azure для Java из указанного репозитория.
  5. Создайте приложение Java, в котором будут использоваться примеры, приведенные в этой статье.

Настройка приложения для доступа к Хранилищу таблиц

Добавьте приведенную ниже запись в раздел dependencies файла pom.xml.

<dependency>
  <groupId>com.azure</groupId>
  <artifactId>azure-data-tables</artifactId>
  <version>12.1.1</version>
</dependency>

Затем, если для доступа к таблицам нужно использовать API-интерфейсы таблиц Azure, добавьте следующие инструкции import в верхнюю часть файла Java.

// Include the following imports to use table APIs
import com.azure.data.tables.TableClient;
import com.azure.data.tables.TableClientBuilder;
import com.azure.data.tables.TableServiceClient;
import com.azure.data.tables.TableServiceClientBuilder;
import com.azure.data.tables.models.ListEntitiesOptions;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableEntityUpdateMode;
import com.azure.data.tables.models.TableTransactionAction;
import com.azure.data.tables.models.TableTransactionActionType;

Добавление строки подключения

Вы можете подключиться к учетной записи хранения Azure или учетной записи Azure Cosmos DB для таблицы. Получите строку подключения на основе типа используемой учетной записи.

Добавление строки подключения к службе хранилища Azure

Клиент таблиц Azure может использовать строку подключения с целью хранения конечных точек и учетных данных для доступа к службам управления данными. При работе в клиентском приложении предоставьте ему строку подключения к службе хранилища в приведенном ниже формате, указав имя учетной записи хранения и первичный ключ доступа для этой учетной записи в качестве значений параметров AccountName и AccountKey. Эти значения вы можете найти на портале Azure.

В этом примере показано, как объявить статическое поле для размещения строки подключения:

// Define the connection-string with your values.
public final String connectionString =
    "DefaultEndpointsProtocol=http;" +
    "AccountName=your_storage_account;" +
    "AccountKey=your_storage_account_key;" +
    "EndpointSuffix=core.windows.net";

Добавление Azure Cosmos DB для таблиц строка подключения

Учетная запись Azure Cosmos DB использует строку подключения для хранения учетных данных и конечной точки таблицы. При работе в клиентском приложении предоставьте ему строку подключения к Azure Cosmos DB в приведенном ниже формате, указав имя учетной записи Azure Cosmos DB и первичный ключ доступа для этой учетной записи в качестве значений параметров AccountName и AccountKey. Эти значения вы можете найти на портале Azure.

В этом примере показано, как объявить статическое поле для размещения строки подключения к Azure Cosmos DB:

public final String connectionString =
    "DefaultEndpointsProtocol=https;" + 
    "AccountName=your_cosmosdb_account;" + 
    "AccountKey=your_account_key;" + 
    "TableEndpoint=https://your_endpoint;";

Если приложение выполняется в роли на платформе Azure, строку подключения можно сохранить в файле конфигурации службы (ServiceConfiguration.cscfg), к которому можно обратиться с помощью метода System.getenv. Ниже приведен пример получения строки подключения из элемента Setting с именем ConnectionString в файле конфигурации службы:

// Retrieve storage account from connection-string.
String connectionString = System.getenv("ConnectionString");

Также вы можете сохранить строку подключения в файле проекта config.properties.

connectionString = DefaultEndpointsProtocol=https;AccountName=your_account;AccountKey=your_account_key;TableEndpoint=https://your_table_endpoint/

В приведенных ниже примерах предполагается, что вы использовали один из описанных выше методов для получения строки подключения к хранилищу.

Создание таблицы

Объект TableServiceClient позволяет взаимодействовать со службой таблиц: создавать, перечислять и удалять таблицы. Приведенный ниже код создает объект TableServiceClient и использует его для создания нового объекта TableClient, который представляет таблицу Employees.

try
{
    final String tableName = "Employees";

    // Create a TableServiceClient with a connection string.
    TableServiceClient tableServiceClient = new TableServiceClientBuilder()
        .connectionString(connectionString)
        .buildClient();

    // Create the table if it not exists.
    TableClient tableClient = tableServiceClient.createTableIfNotExists(tableName);

}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Перечисление таблиц

Чтобы получить список таблиц, вызовите метод TableServiceClient.listTables для извлечения пригодного к итерации списка имен таблиц.

try
{
    // Create a TableServiceClient with a connection string.
    TableServiceClient tableServiceClient = new TableServiceClientBuilder()
        .connectionString(connectionString)
        .buildClient();

    // Loop through a collection of table names.
    tableServiceClient.listTables().forEach(tableItem -> 
        System.out.printf(tableItem.getName())
    );
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Добавление сущности в таблицу

Следующий код создает новый экземпляр класса TableEntity с подлежащими сохранению данными клиента. Код вызывает метод upsertEntity для объекта TableClient. Этот метод либо вставляет в таблицу Employees новую сущность Customer (Клиент), либо заменяет эту сущность, если она уже существует.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
     TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Create a new employee TableEntity.
    String partitionKey = "Sales";
    String rowKey = "0001";
    Map<String, Object> personalInfo= new HashMap<>();
    personalInfo.put("FirstName", "Walter");
    personalInfo.put("LastName", "Harp");
    personalInfo.put("Email", "Walter@contoso.com");
    personalInfo.put("PhoneNumber", "425-555-0101");
    TableEntity employee = new TableEntity(partitionKey, rowKey).setProperties(personalInfo);
        
    // Upsert the entity into the table
    tableClient.upsertEntity(employee);
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Вставка пакета сущностей

Вы можете вставить пакет сущностей в таблицу в одной операции записи. Следующий код создает объект List<TableTransactionAction> и добавляет в него три операции upsert. Для добавления каждой операции необходимо создать новый объект TableEntity, задать его свойства, а затем вызвать метод submitTransaction для объекта TableClient.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    String partitionKey = "Sales";
    List<TableTransactionAction> tableTransactionActions = new ArrayList<>();
    
    Map<String, Object> personalInfo1 = new HashMap<>();
    personalInfo1.put("FirstName", "Jeff");
    personalInfo1.put("LastName", "Smith");
    personalInfo1.put("Email", "Jeff@contoso.com");
    personalInfo1.put("PhoneNumber", "425-555-0104");
    
    // Create an entity to add to the table.
    tableTransactionActions.add(new TableTransactionAction(
        TableTransactionActionType.UPSERT_MERGE,
        new TableEntity(partitionKey, "0001")
            .setProperties(personalInfo1)
    ));
    
    Map<String, Object> personalInfo2 = new HashMap<>();
    personalInfo2.put("FirstName", "Ben");
    personalInfo2.put("LastName", "Johnson");
    personalInfo2.put("Email", "Ben@contoso.com");
    personalInfo2.put("PhoneNumber", "425-555-0102");
    
    // Create another entity to add to the table.
    tableTransactionActions.add(new TableTransactionAction(
        TableTransactionActionType.UPSERT_MERGE,
        new TableEntity(partitionKey, "0002")
            .setProperties(personalInfo2)
    ));
    
    Map<String, Object> personalInfo3 = new HashMap<>();
    personalInfo3.put("FirstName", "Denise");
    personalInfo3.put("LastName", "Rivers");
    personalInfo3.put("Email", "Denise@contoso.com");
    personalInfo3.put("PhoneNumber", "425-555-0103");
    
    // Create a third entity to add to the table.
    tableTransactionActions.add(new TableTransactionAction(
        TableTransactionActionType.UPSERT_MERGE,
        new TableEntity(partitionKey, "0003")
            .setProperties(personalInfo3)
    ));

    // Submit transaction on the "Employees" table.
    tableClient.submitTransaction(tableTransactionActions);
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Некоторые другие примечания к пакетным операциям:

  • В отдельном пакете можно выполнить до 100 операций вставки, удаления, объединения, замены, вставки или замены и вставки или замены операций в любом сочетании.
  • Пакетная операция может иметь операцию извлечения, если она является единственной операцией в пакете.
  • У всех сущностей в одной пакетной операции должен быть одинаковый ключ раздела.
  • Максимальный объем полезных данных пакетной операции составляет 4 МБ.

Получение всех сущностей в разделе

Чтобы запросить из таблицы сущности раздела, можно использовать ListEntitiesOptions. Вызовите ListEntitiesOptions.setFilter, чтобы создать запрос для определенной таблицы, который возвращает результаты заданного типа. Приведенный ниже код задает фильтр для сущностей с ключом раздела Sales. Когда выполняется запрос путем вызова listEntities из объекта TableClient, ответ содержит Iterator для TableEntity. Затем можно передать полученное значение Iterator в цикл ForEach для обработки результатов. Этот код выводит на консоль поля каждой сущности в результатах запроса.

try
{
    // Define constants for filters.
    final String PARTITION_KEY = "PartitionKey";
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Create a filter condition where the partition key is "Sales".
    ListEntitiesOptions options = new ListEntitiesOptions().setFilter(PARTITION_KEY + " eq 'Sales'");

    // Loop through the results, displaying information about the entities.
    tableClient.listEntities(options, null, null).forEach(tableEntity -> {
        System.out.println(tableEntity.getPartitionKey() +
            " " + tableEntity.getRowKey() +
            "\t" + tableEntity.getProperty("FirstName") +
            "\t" + tableEntity.getProperty("LastName") +
            "\t" + tableEntity.getProperty("Email") +
            "\t" + tableEntity.getProperty("PhoneNumber"));
    });
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Получение диапазона сущностей в разделе

Если вы не хотите запрашивать все сущности в разделе, укажите диапазон с помощью операторов сравнения в фильтре. Приведенный ниже код объединяет два фильтра для получения всех сущностей в разделе Sales с ключом строки от 0001 до 0004. После чего результаты запроса выводятся на консоль. Если вы используете сущности, добавленные в таблицу во время работы с разделом о пакетной вставке, то на этот раз возвращаются только две сущности (Ben и Denise).

try
{
    // Define constants for filters.
    final String PARTITION_KEY = "PartitionKey";
    final String ROW_KEY = "RowKey";
    final String tableName = "Employees";

    // Create a TableServiceClient with a connection string.
    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Create a filter condition where the partition key is "Sales".
    ListEntitiesOptions options = new ListEntitiesOptions().setFilter(PARTITION_KEY + " eq 'Sales' AND " + ROW_KEY + " lt '0004' AND " + ROW_KEY + " gt '0001'");
    
    // Loop through the results, displaying information about the entities.
    tableClient.listEntities(options, null, null).forEach(tableEntity -> {
        System.out.println(tableEntity.getPartitionKey() +
            " " + tableEntity.getRowKey() +
            "\t" + tableEntity.getProperty("FirstName") +
            "\t" + tableEntity.getProperty("LastName") +
            "\t" + tableEntity.getProperty("Email") +
            "\t" + tableEntity.getProperty("PhoneNumber"));
    });
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Извлечение одной сущности

Можно написать запрос для получения отдельной сущности. Следующий код вызывает TableClient.getEntity с параметрами ключа раздела и ключа строки, позволяя получить сущность сотрудника Jeff Smith. Это дает такой же результат, как создание ListEntitiesOptions и применение фильтров. При выполнении операция извлечения возвращает только одну сущность, а не коллекцию. Значение null возвращается, если ни одна сущность не подходит по ключам раздела и строки. Указание ключа раздела и ключа строки в запросе — самый быстрый способ для получения одной сущности из службы таблиц .

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Get the specific entity.
    TableEntity specificEntity = tableClient.getEntity("Sales", "0001");

    // Output the entity.
    if (specificEntity != null)
    {
        System.out.println(specificEntity.getPartitionKey() +
            " " + specificEntity.getRowKey() +
            "\t" + specificEntity.getProperty("FirstName") +
            "\t" + specificEntity.getProperty("LastName") +
            "\t" + specificEntity.getProperty("Email") +
            "\t" + specificEntity.getProperty("PhoneNumber"));
    }
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Изменение сущности

Чтобы изменить сущность, извлеките ее из службы таблиц, измените объект сущности и сохраните изменения в службе таблиц с помощью операции замены или объединения. Следующий код изменяет существующий номер телефона клиента. Вместо вызова tableClient.upsertEntity (как мы делали при вставке) этот код вызывает tableClient.updateEntity.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Get the specific entity.
    TableEntity specificEntity = tableClient.getEntity("Sales", "0001");

    // Specify a new phone number
    specificEntity.getProperties().put("PhoneNumber", "425-555-0105");

    // Update the specific entity
    tableClient.updateEntity(specificEntity, TableEntityUpdateMode.REPLACE);
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Запрос подмножества свойств сущности

Запрос к таблице может получить лишь несколько свойств сущности. Этот метод, который называется "проекцией", снижает потребление пропускной способности и может повысить производительность запросов, особенно для крупных сущностей. Запрос в следующем коде использует метод ListEntitiesOptions.setSelect, чтобы возвратить только адреса электронной почты сущностей в таблице.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Create a filter condition that retrieves only the Email property.
    List<String> attributesToRetrieve = new ArrayList<>();
    attributesToRetrieve.add("Email");
    
    ListEntitiesOptions options = new ListEntitiesOptions().setSelect(attributesToRetrieve);

    // Loop through the results, displaying the Email values.
    tableClient.listEntities(options, null, null).forEach(tableEntity -> {
        System.out.println(tableEntity.getProperty("Email"));
    });
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Вставка и замена сущностей

Часто требуется добавить сущность в таблицу, не зная, присутствует ли она там. Операция вставки или замены позволяет выполнить один запрос. Этот запрос либо вставляет сущность, если она не существует, либо заменяет существующую. В продолжение материала предыдущих примеров следующий код вставляет или заменяет сущность "Walter Harp". После создания новой сущности этот код вызывает метод TableClient.upsertEntity.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Create a new table entity.
    Map<String, Object> properties = new HashMap<>();
    properties.put("FirstName", "Walter");
    properties.put("LastName", "Harp");
    properties.put("Email", "Walter@contoso.com");
    properties.put("PhoneNumber", "425-555-0101");
        
    TableEntity newEmployee = new TableEntity("Sales", "0004")
        .setProperties(properties);
        
    // Add the new customer to the Employees table.
    tableClient.upsertEntity(newEmployee);
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Удаление сущности

Сущность можно удалить, указав ключ раздела и ключ строки с помощью TableClient.deleteEntity.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Delete the entity for partition key 'Sales' and row key '0001' from the table.
    tableClient.deleteEntity("Sales", "0001");
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Удалить таблицу

Наконец, указанный ниже код удаляет таблицу из учетной записи. После удаления таблицы ее нельзя создать заново в течение примерно 40 секунд.

try
{
    final String tableName = "Employees";

    // Create a TableClient with a connection string and a table name.
    TableClient tableClient = new TableClientBuilder()
        .connectionString(connectionString)
        .tableName(tableName)
        .buildClient();

    // Delete the table and all its data.
    tableClient.deleteTable();
}
catch (Exception e)
{
    // Output the stack trace.
    e.printStackTrace();
}

Совет

См. примеры кода в репозитории службы хранилища Azure

Полные и простые в применении примеры кода для службы хранилища Azure можно скачать и запустить отсюда.

Следующие шаги

Дополнительные сведения см. в разделе Azure for Java developers (Azure для разработчиков Java).