Como usar a biblioteca de clientes das Tabelas do Azure para Java

APLICA-SE AO: Table

Dica

O conteúdo deste artigo se aplica ao Armazenamento de Tabelas do Azure e ao Azure Cosmos DB for Table. A API for Table é uma oferta premium para armazenamento de tabelas que oferece tabelas com taxa de transferência otimizada, distribuição global e índices secundários automáticos.

Este artigo mostra como criar tabelas, armazenar dados e realizar operações CRUD nesses dados. Os exemplos são escritos em Java e usam a biblioteca de clientes das Tabelas do Azure para Java. Os cenários abrangidos incluem criar, listar e excluir tabelas, além de inserir, consultar, modificar e excluir entidades em uma tabela. Para obter mais informações sobre tabelas, consulte a seção Próximas etapas .

Importante

A última versão da biblioteca de clientes das Tabelas do Azure que dá suporte ao Armazenamento de Tabelas e à Tabela do Azure Cosmos DB é a 12+.

Criar uma conta de serviço do Azure

Você pode trabalhar com tabelas usando o Armazenamento de Tabelas do Azure ou o Azure Cosmos DB. Para saber mais sobre as diferenças entre as ofertas de tabela desses dois serviços, confira a Visão geral da API para tabela. Você precisará criar uma conta para o serviço que pretende usar. As seções a seguir mostram como criar as contas do Armazenamento de Tabelas do Azure e do Azure Cosmos DB, no entanto, você pode usar apenas um deles.

Crie uma conta de armazenamento do Azure

A maneira mais fácil de criar uma conta de armazenamento do Azure é usando o portal do Azure. Para saber mais, consulte Criar uma conta de armazenamento.

Você também pode criar uma conta de armazenamento do Azure usando o Azure PowerShell ou a CLI do Azure.

Se você preferir não criar uma conta de armazenamento no momento, também poderá usar o Emulador de Armazenamento do Azure para executar e testar o seu código em um ambiente local. Para saber mais, confira Usar o Emulador de Armazenamento do Azure para desenvolvimento e teste.

Criar uma conta do BD Cosmos do Azure

Para obter instruções sobre como criar uma conta do Azure Cosmos DB for Table, veja Criar uma conta de banco de dados.

Criar um aplicativo Java

Para usar os exemplos neste artigo:

  1. Instale o JDK (Java Development Kit).
  2. Crie uma conta de armazenamento do Azure ou do Azure Cosmos DB em sua assinatura do Azure.
  3. Verifique se o sistema de desenvolvimento atende aos requisitos mínimos e às dependências listadas no repositório da biblioteca de clientes das Tabelas do Azure para Java no GitHub.
  4. Siga as instruções para baixar e instalar as Bibliotecas de Armazenamento do Azure para Java em seu sistema por meio desse repositório.
  5. Crie um aplicativo Java que usa os exemplos neste artigo.

Configurar o aplicativo para acessar o Armazenamento de Tabelas

Adicione a seguinte entrada à seção dependencies de seu arquivo pom.xml:

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

Em seguida, adicione as seguintes instruções import à parte superior do arquivo Java em que deseja usar as APIs das Tabelas do Azure para acessar as tabelas:

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

Adicionar sua cadeia de conexão

Você pode se conectar à conta de armazenamento do Azure ou à conta do Azure Cosmos DB for Table. Obtenha a cadeia de conexão com base no tipo de conta que está usando.

Adicionar uma cadeia de conexão do Armazenamento do Azure

Um cliente das Tabelas do Azure pode usar uma cadeia de conexão para armazenar pontos de extremidade e credenciais para acessar serviços de gerenciamento de dados. Ao executar em um aplicativo cliente, você precisa fornecer a cadeia de conexão de armazenamento no formato a seguir, usando o nome de sua conta de armazenamento e a tecla de acesso primário da conta de armazenamento listada no portal do Azure para os valores de AccountName e AccountKey.

Este exemplo mostra como você pode declarar um campo estático para armazenar a cadeia de conexão:

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

Adicionar uma cadeia de conexão do Azure Cosmos DB for Table

Uma conta de banco de dados do Azure Cosmos DB usa uma cadeia de caracteres de conexão para armazenar o ponto de extremidade de tabela e suas credenciais. Ao executar em um aplicativo cliente, é necessário fornecer a cadeia de conexão de armazenamento do Azure Cosmos DB no formato a seguir, usando o nome de sua conta do Azure Cosmos DB e a chave de Acesso primário da conta de armazenamento listada no Portal do Azure para os valores de AccountName e AccountKey.

Este exemplo mostra como você pode declarar um campo estático para armazenar a cadeia de conexão do Azure Cosmos DB:

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

Em um aplicativo em execução dentro de uma função no Azure, você pode armazenar essa cadeia de caracteres no arquivo de configuração de serviço, ServiceConfiguration.cscfg. Você pode acessá-lo com uma chamada para o método System.getenv. Veja um exemplo de como obter a cadeia de conexão de um elemento Setting denominado ConnectionString no arquivo de configuração de serviço:

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

Você também pode armazenar a cadeia de conexão no arquivo de config.properties do seu projeto:

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

Os exemplos abaixo pressupõem que você usou um desses métodos para obter a cadeia de conexão do armazenamento.

Criar uma tabela

Um objeto TableServiceClient permite que você interaja com o serviço Tabelas para criar, listar e excluir tabelas. O código a seguir cria um objeto TableServiceClient e o usa para criar um objeto TableClient, o qual representa uma tabela chamada 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();
}

Listar as tabelas

Para obter uma lista de tabelas, chame o método TableServiceClient.listTables para recuperar uma lista iterável de nomes de tabela.

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();
}

Adicionar uma entidade a uma tabela

O código a seguir cria uma instância da classe TableEntity com alguns dados do cliente a serem armazenados. O código chama o método upsertEntity no objeto TableClient. Esse método insere a nova entidade do cliente na tabela Employees ou substitui a entidade caso ela já exista.

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();
}

Inserir um lote de entidades

Você pode inserir um lote de entidades ao serviço Tabela em uma operação de gravação. O código a seguir cria um objeto List<TableTransactionAction> e adiciona três operações upsert a ele. Cada operação é adicionada criando um objeto TableEntity, definindo suas propriedades e chamando o método submitTransaction no objeto 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();
}

Algumas outras observações sobre as operações em lote:

  • Você pode executar até 100 operações de inserção, exclusão, mesclagem, substituição, inserção ou mesclagem e inserção ou substituição em qualquer combinação em um único lote.
  • Uma operação em lote pode ter uma operação de recuperação se ela for a única operação no lote.
  • Todas as entidades em uma única operação em lote devem ter a mesma chave de partição.
  • Uma operação em lote está limitada a uma carga de dados de 4 MB.

Recuperar todas as entidades em uma partição

Para consultar uma tabela de todas as entidades em uma partição, use ListEntitiesOptions. Chame ListEntitiesOptions.setFilter para criar uma consulta em uma determinada tabela que retorna um tipo de resultado especificado. O código a seguir especifica um filtro para entidades em que Sales é a chave da partição. Quando a consulta é executada com uma chamada para listEntities no objeto TableClient, ela retorna um Iterator igual a TableEntity. Com isso, é possível usar o Iterator retornado em um loop "ForEach" para consumir os resultados. Esse código imprime os campos de cada entidade nos resultados da consulta no console.

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();
}

Recuperar um intervalo de entidades em uma partição

Se não quiser consultar todas as entidades em uma partição, especifique um intervalo usando operações de comparação em um filtro. O código a seguir combina dois filtros para obter todas as entidades na partição Sales com uma chave de linha entre '0001' e '0004'. Em seguida, eleimprime os resultados da consulta. Se você usar as entidades adicionadas à tabela na seção de inserção do lote deste guia, apenas duas entidades serão retornadas desta vez (Ben e 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();
}

Recuperar uma única entidade

Você pode escrever uma consulta para recuperar uma entidade única e específica. O código a seguir chama TableClient.getEntity com uma chave de partição e parâmetros da chave de linha para recuperar a entidade para o funcionário "Jeff Smith", em vez de criar um ListEntitiesOptions e usar filtros para executar a mesma tarefa. Quando executada, a operação de recuperação retorna apenas uma entidade, em vez de uma coleção. Um valor null será retornado se nenhuma entidade tiver uma correspondência exata de chave de partição e chave de linha. Especificar chaves de partição e de linha em uma consulta é a maneira mais rápida de recuperar uma única entidade de serviço Table.

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();
}

Modificar uma entidade

Para modificar uma entidade, recupere-a do serviço Tabela, altere o objeto de entidade e, em seguida, salve as alterações novamente no serviço Tabela com uma operação de substituição ou mesclagem. O código a seguir altera o número de telefone de um cliente existente. Em vez de chamar tableClient.upsertEntity como fizemos para inserir, esse código chama 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();
}

consultar um subconjunto de propriedades da entidade

Uma consulta a uma tabela pode recuperar apenas algumas propriedades de uma entidade. Essa técnica, chamada projeção, reduz a largura de banda e pode melhorar o desempenho da consulta, principalmente para grandes entidades. A consulta no código a seguir usa o método ListEntitiesOptions.setSelect para retornar apenas os endereços de email das entidades na tabela.

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();
}

Inserir ou substituir uma entidade

Em geral, você deseja adicionar uma entidade a uma tabela sem saber se ela já existe na tabela. Uma operação de inserção ou substituição permite fazer uma só solicitação. Essa solicitação insere a entidade quando ela não existe ou substitui a entidade existente. Com base nos exemplos anteriores, o código a seguir insere ou substitui a entidade para "Walter Harp". Depois de criar uma entidade, esse código chama o método 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();
}

Excluir uma entidade

Você pode excluir uma entidade fornecendo sua chave de partição e chave de linha por meio de 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();
}

Excluir uma tabela

Por fim, o código a seguir exclui uma tabela de uma conta. Por cerca de 40 segundos depois de excluir uma tabela, não é possível recriá-la.

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();
}

Dica

Confira o repositório de exemplos de código do Armazenamento do Azure

Para exemplos de código fácil de usar ponta a ponta do Armazenamento do Azure que você pode baixar e executar, consulte nossa lista de Exemplos de Armazenamento do Azure.

Próximas etapas

Para saber mais, visite Azure para desenvolvedores Java.