

# Programação com o DynamoDB e os AWS SDKs
<a name="Programming"></a>

Esta seção aborda tópicos relacionados a desenvolvedores. Em vez disso, se você deseja executar exemplos de código, consulte [Executar os exemplos de código neste Guia do desenvolvedor](CodeSamples.md). 

**nota**  
Em dezembro de 2017, a AWS iniciou o processo de migração de todos os endpoints do Amazon DynamoDB para usar certificados seguros emitidos pelo Amazon Trust Services (ATS). Para obter mais informações, consulte [Solução de problemas de estabelecimento de conexão SSL/TLS com o DynamoDB](ats-certs.md). 

**Topics**
+ [Visão geral do suporte a AWS SDKs para o DynamoDB](Programming.SDKOverview.md)
+ [Programar o Amazon DynamoDB com Python e Boto3](programming-with-python.md)
+ [Programar o Amazon DynamoDB com JavaScript](programming-with-javascript.md)
+ [Programar o DynamoDB com o AWS SDK for Java 2.x](ProgrammingWithJava.md)
+ [Tratamento de erros com o DynamoDB](Programming.Errors.md)
+ [Usar o DynamoDB com um AWS SDK](sdk-general-information-section.md)

# Visão geral do suporte a AWS SDKs para o DynamoDB
<a name="Programming.SDKOverview"></a>

O diagrama a seguir fornece uma visão geral de alto nível da programação de aplicações do Amazon DynamoDB usando os AWS SDKs.

![\[Modelo de programação para usar o DynamoDB com SDKs da AWS.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/SDKSupport.png)


1. Você pode escrever uma aplicação usando um AWS SDK para a sua linguagem de programação.

1. Cada AWS SDK fornece uma ou mais interfaces programáticas para trabalhar com o DynamoDB. As interfaces específicas disponíveis dependem de qual linguagem de programação e AWS SDK você utiliza. Entre as opções estão:
   + [Interfaces de baixo nível que funcionam com o DynamoDB](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.LowLevel)
   + [Interfaces de documentos que funcionam com o DynamoDB](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.Document)
   + [Interfaces de persistência de objetos que funcionam com o DynamoDB](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.Mapper)
   + [Interfaces de alto nível](HigherLevelInterfaces.md)

1. O AWS SDKconstrói solicitações HTTP(S) para uso com a API de baixo nível do DynamoDB.

1. O AWS SDK envia a solicitação ao endpoint do DynamoDB.

1. O DynamoDB executa a solicitação. Se a solicitação for bem-sucedida, o DynamoDB retornará um código de resposta HTTP 200 (OK). Se a solicitação não for bem-sucedida, o DynamoDB retornará um código de erro HTTP e uma mensagem de erro.

1. O AWS SDK processa a resposta e a propaga de volta para sua aplicação.

Cada um dos AWS SDKsfornece serviços importantes à sua aplicação, incluindo os seguintes:
+ Formatação de solicitações HTTP(S) e serialização de parâmetros de solicitação.
+ Geração de uma assinatura criptográfica para cada solicitação.
+ Encaminhamento de solicitações a um endpoint do DynamoDB e recebimento de respostas do DynamoDB.
+ Extração dos resultados dessas respostas.
+ Implementação da lógica de novas tentativas básicas em caso de erros.

Não é necessário escrever código para qualquer uma dessas tarefas.

**nota**  
Para obter mais informações sobre AWS SDKs, incluindo instruções de instalação e documentação, consulte [Ferramentas para a Amazon Web Services](https://aws.amazon.com/tools).

## Suporte SDK para endpoints baseados em contas da AWS
<a name="Programming.SDKs.endpoints"></a>

A AWS está implementando o suporte do SDK para endpoints baseados em contas da AWS para o DynamoDB, começando com o AWS SDK for Java V1 em 4 de setembro de 2024. Esses novos endpoints ajudam a AWS garantir alto desempenho e escalabilidade. Os SDKs atualizados usarão automaticamente os novos endpoints, que têm o formato `https://(account-id).ddb.(region).amazonaws.com`

Se você usar uma única instância de um cliente SDK para fazer solicitações para várias contas, sua aplicação terá menos oportunidades de reutilizar conexões. A AWS recomenda modificar as aplicações para se conectar a menos contas por instância do cliente SDK. Uma alternativa é configurar seu cliente SDK para continuar usando endpoints regionais por meio da configuração `ACCOUNT_ID_ENDPOINT_MODE`, conforme documentado no [https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html).

# Interfaces programáticas que funcionam com o DynamoDB
<a name="Programming.SDKs.Interfaces"></a>

Cada [AWS SDK](https://aws.amazon.com/tools) fornece uma ou mais interfaces programáticas para trabalhar com o Amazon DynamoDB. Essas interfaces variam de wrappers simples de baixo nível do DynamoDB a camadas de persistência orientadas a objetos. As interfaces disponíveis variam dependendo do AWS SDK e da linguagem de programação que você utiliza.

![\[Interfaces programáticas disponíveis em diferentes SDKs da AWS para trabalhar com o DynamoDB.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/SDKSupport.SDKInterfaces.png)


A seção a seguir destaca algumas das interfaces disponíveis, usando o AWS SDK para Java como exemplo. (Nem todas as interfaces estão disponíveis em todos os AWS SDKs.)

**Topics**
+ [Interfaces de baixo nível que funcionam com o DynamoDB](#Programming.SDKs.Interfaces.LowLevel)
+ [Interfaces de documentos que funcionam com o DynamoDB](#Programming.SDKs.Interfaces.Document)
+ [Interfaces de persistência de objetos que funcionam com o DynamoDB](#Programming.SDKs.Interfaces.Mapper)

## Interfaces de baixo nível que funcionam com o DynamoDB
<a name="Programming.SDKs.Interfaces.LowLevel"></a>

O AWS SDK de cada linguagem específica fornece uma interface de baixo nível para o Amazon DynamoDB, com métodos que se assemelham a solicitações de API de baixo nível do DynamoDB.

Em alguns casos, você precisará identificar os tipos de dados dos atributos usando [Descritores de tipo de dados](Programming.LowLevelAPI.md#Programming.LowLevelAPI.DataTypeDescriptors), como `S` para strings ou `N` para números.

**nota**  
Uma interface de baixo nível está disponível no AWS SDK de cada linguagem específica.

O seguinte programa Java usa a interface de baixo nível do AWS SDK para Java. 

### Exemplo de interface de baixo nível
<a name="low-level-example"></a>

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 *
 * To get an item from an Amazon DynamoDB table using the AWS SDK for Java V2,
 * its better practice to use the
 * Enhanced Client, see the EnhancedGetItem example.
 */
public class GetItem {
    public static void main(String[] args) {
        final String usage = """

                Usage:
                    <tableName> <key> <keyVal>

                Where:
                    tableName - The Amazon DynamoDB table from which an item is retrieved (for example, Music3).\s
                    key - The key used in the Amazon DynamoDB table (for example, Artist).\s
                    keyval - The key value that represents the item to get (for example, Famous Band).
                """;

        if (args.length != 3) {
            System.out.println(usage);
            System.exit(1);
        }

        String tableName = args[0];
        String key = args[1];
        String keyVal = args[2];
        System.out.format("Retrieving item \"%s\" from \"%s\"\n", keyVal, tableName);
        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        getDynamoDBItem(ddb, tableName, key, keyVal);
        ddb.close();
    }

    public static void getDynamoDBItem(DynamoDbClient ddb, String tableName, String key, String keyVal) {
        HashMap<String, AttributeValue> keyToGet = new HashMap<>();
        keyToGet.put(key, AttributeValue.builder()
                .s(keyVal)
                .build());

        GetItemRequest request = GetItemRequest.builder()
                .key(keyToGet)
                .tableName(tableName)
                .build();

        try {
            // If there is no matching item, GetItem does not return any data.
            Map<String, AttributeValue> returnedItem = ddb.getItem(request).item();
            if (returnedItem.isEmpty())
                System.out.format("No item found with the key %s!\n", key);
            else {
                Set<String> keys = returnedItem.keySet();
                System.out.println("Amazon DynamoDB table attributes: \n");
                for (String key1 : keys) {
                    System.out.format("%s: %s\n", key1, returnedItem.get(key1).toString());
                }
            }

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
}
```

## Interfaces de documentos que funcionam com o DynamoDB
<a name="Programming.SDKs.Interfaces.Document"></a>

Muitos AWS SDKs fornecem uma interface de documento, permitindo que você realize operações de plano de dados (criar, ler, atualizar, excluir) em tabelas e índices. Com uma interface de documento, você não precisa especificar [Descritores de tipo de dados](Programming.LowLevelAPI.md#Programming.LowLevelAPI.DataTypeDescriptors). Os tipos de dados estão implícitos pela semântica dos próprios dados. Estes AWS SDKs também fornecem métodos para converter facilmente documentos JSON de/em tipos de dados nativos do Amazon DynamoDB.

**nota**  
Interfaces de documentos estão disponíveis nos AWS SDKs para [Java](https://aws.amazon.com/sdk-for-java), [.NET](https://aws.amazon.com/sdk-for-net), [Node.js](https://aws.amazon.com/sdk-for-node-js) e [JavaScript SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/).

O seguinte programa Java usa a interface de documento do AWS SDK para Java. O programa cria um objeto `Table` que representa a tabela `Music` e depois solicita que esse objeto use `GetItem` para recuperar uma música. Em seguida, o programa imprime o ano em que a canção foi lançada.

A classe `software.amazon.dynamodb.document.DynamoDB` implementa a interface de documento do DynamoDB. Observe como `DynamoDB` atua como um wrapper em torno do cliente de baixo nível (`AmazonDynamoDB`).

### Exemplo de interface de documentos
<a name="document-level-example"></a>

```
package com.amazonaws.codesamples.gsg;

import software.amazon.dynamodb.AmazonDynamoDB;
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import software.amazon.dynamodb.document.DynamoDB;
import software.amazon.dynamodb.document.GetItemOutcome;
import software.amazon.dynamodb.document.Table;

public class MusicDocumentDemo {

    public static void main(String[] args) {

        AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
        DynamoDB docClient = new DynamoDB(client);

        Table table = docClient.getTable("Music");
        GetItemOutcome outcome = table.getItemOutcome(
                "Artist", "No One You Know",
                "SongTitle", "Call Me Today");

        int year = outcome.getItem().getInt("Year");
        System.out.println("The song was released in " + year);

    }
}
```

## Interfaces de persistência de objetos que funcionam com o DynamoDB
<a name="Programming.SDKs.Interfaces.Mapper"></a>

Alguns AWS SDKs fornecem uma interface de persistência de objetos em que você não realiza operações de plano de dados diretamente. Em vez disso, você cria objetos que representam itens em índices e tabelas do Amazon DynamoDB e interage apenas com esses objetos. Isso permite que você escreva um código centrado em objetos, em vez de um código centrado no banco de dados.

**nota**  
Interfaces de persistência de objetos estão disponíveis nos AWS SDKs for Java e .NET. Para obter mais informações, consulte [Interfaces de programação de nível superior para o DynamoDB](HigherLevelInterfaces.md) para o DynamoDB.

### Exemplo de interface de persistência de objetos
<a name="mapper-level-example"></a>

```
import com.example.dynamodb.Customer;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
```

```
import com.example.dynamodb.Customer;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.GetItemEnhancedRequest;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;

/*
 * Before running this code example, create an Amazon DynamoDB table named Customer with these columns:
 *   - id - the id of the record that is the key. Be sure one of the id values is `id101`
 *   - custName - the customer name
 *   - email - the email value
 *   - registrationDate - an instant value when the item was added to the table. These values
 *                        need to be in the form of `YYYY-MM-DDTHH:mm:ssZ`, such as 2022-07-11T00:00:00Z
 *
 * Also, ensure that you have set up your development environment, including your credentials.
 *
 * For information, see this documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */

public class EnhancedGetItem {
    public static void main(String[] args) {
        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
                .dynamoDbClient(ddb)
                .build();

        getItem(enhancedClient);
        ddb.close();
    }

    public static String getItem(DynamoDbEnhancedClient enhancedClient) {
        Customer result = null;
        try {
            DynamoDbTable<Customer> table = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
            Key key = Key.builder()
                    .partitionValue("id101").sortValue("tred@noserver.com")
                    .build();

            // Get the item by using the key.
            result = table.getItem(
                    (GetItemEnhancedRequest.Builder requestBuilder) -> requestBuilder.key(key));
            System.out.println("******* The description value is " + result.getCustName());

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        return result.getCustName();
    }
}
```

# Interfaces de programação de nível superior para o DynamoDB
<a name="HigherLevelInterfaces"></a>

Os AWS SDKs fornecem aplicações com interfaces de baixo nível para trabalhar com o Amazon DynamoDB. Estes métodos e classes no lado do cliente correspondem diretamente à API de baixo nível do DynamoDB. No entanto, muitos desenvolvedores experimentam uma sensação de desconexão, ou *incompatibilidade de impedância*, quando precisam mapear tipos de dados complexos para itens em uma tabela de banco de dados. Com uma interface de banco de dados de baixo nível, os desenvolvedores precisam escrever métodos para a leitura ou a gravação de dados de objetos em tabelas de banco de dados e vice-versa. A quantidade de código extra necessária para cada combinação de tipo de objeto e tabela de banco de dados pode parecer esmagadora.

Para simplificar o desenvolvimento, os AWS SDKs for Java e .NET fornecem interfaces adicionais com níveis mais altos de abstração. As interfaces de nível superior para o DynamoDB permitem que você defina as relações entre objetos no seu programa e as tabelas de banco de dados que armazenam os dados desses objetos. Depois de definir esse mapeamento, você chama métodos de objeto simples, como `save`, `load` ou `delete`, e as operações de baixo nível do DynamoDB subjacente são invocadas automaticamente em seu nome. Isso permite que você escreva um código centrado em objetos, em vez de um código centrado no banco de dados.

Interfaces de programação de nível superior para o DynamoDB estão disponíveis nos AWS SDKs for Java e .NET.

**Java**
+ [Java 1.x: DynamoDBMapper](DynamoDBMapper.md)
+ [Java 2.x: Cliente Aprimorado do DynamoDB](DynamoDBEnhanced.md)

**.NET**
+ [Trabalhar com o modelo de documento do .NET no DynamoDB](DotNetSDKMidLevel.md)
+ [Trabalhar com o modelo de persistência de objetos do .NET e o DynamoDB](DotNetSDKHighLevel.md)

# Java 1.x: DynamoDBMapper
<a name="DynamoDBMapper"></a>

**nota**  
O SDK para Java tem duas versões: 1.x e 2.x. O fim do suporte para a versão 1.x foi [anunciado](https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-java-v1-x-on-december-31-2025/) em 12 de janeiro de 2024. Ele está previsto para 31 de dezembro de 2025. Para novos desenvolvimentos, é altamente recomendável que você use a versão 2.x.

O AWS SDK para Java fornece uma classe `DynamoDBMapper`, permitindo mapear classes no lado do cliente para tabelas do Amazon DynamoDB. Para usar `DynamoDBMapper`, defina a relação entre os itens em uma tabela do DynamoDB e as instâncias de objeto correspondentes no seu código. A classe `DynamoDBMapper` permite que você realize várias operações de criação, leitura, atualização e exclusão (CRUD) em itens e execute consultas e verificações em tabelas.

**Topics**
+ [Classe DynamoDBMapper](DynamoDBMapper.Methods.md)
+ [Tipos de dados compatíveis com DynamoDBMapper para Java](DynamoDBMapper.DataTypes.md)
+ [Anotações Java para DynamoDB](DynamoDBMapper.Annotations.md)
+ [Definições de configuração opcionais para DynamoDBMapper](DynamoDBMapper.OptionalConfig.md)
+ [DynamoDB e bloqueio positivo com número de versão](DynamoDBMapper.OptimisticLocking.md)
+ [Mapear dados arbitrários no DynamoDB](DynamoDBMapper.ArbitraryDataMapping.md)
+ [Exemplos de DynamoDBMapper](DynamoDBMapper.Examples.md)

**nota**  
A classe `DynamoDBMapper` não permite criar, atualizar ou excluir tabelas. Para realizar essas tarefas, use em vez disso a interface do SDK para Java de baixo nível.

O SDK para Java fornece um conjunto de tipos de anotações, para que você possa mapear suas classes em tabelas. Por exemplo, considere uma tabela `ProductCatalog` cujo `Id` seja a chave de partição. 

```
ProductCatalog(Id, ...)
```

É possível mapear uma classe no seu aplicativo cliente para a tabela `ProductCatalog`, conforme mostrado no código Java a seguir. Este código define um objeto Java antigo simples (POJO) chamado `CatalogItem` que usa anotações para mapear campos de objeto em nomes de atributos do DynamoDB.

**Example**  

```
package com.amazonaws.codesamples;

import java.util.Set;

import software.amazon.dynamodb.datamodeling.DynamoDBAttribute;
import software.amazon.dynamodb.datamodeling.DynamoDBHashKey;
import software.amazon.dynamodb.datamodeling.DynamoDBIgnore;
import software.amazon.dynamodb.datamodeling.DynamoDBTable;

@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {

    private Integer id;
    private String title;
    private String ISBN;
    private Set<String> bookAuthors;
    private String someProp;

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id; }
    public void setId(Integer id) {this.id = id; }

    @DynamoDBAttribute(attributeName="Title")
    public String getTitle() {return title; }
    public void setTitle(String title) { this.title = title; }

    @DynamoDBAttribute(attributeName="ISBN")
    public String getISBN() { return ISBN; }
    public void setISBN(String ISBN) { this.ISBN = ISBN; }

    @DynamoDBAttribute(attributeName="Authors")
    public Set<String> getBookAuthors() { return bookAuthors; }
    public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; }

    @DynamoDBIgnore
    public String getSomeProp() { return someProp; }
    public void setSomeProp(String someProp) { this.someProp = someProp; }
}
```

No código anterior, a anotação `@DynamoDBTable` mapeia a classe `CatalogItem` para a tabela `ProductCatalog`. Você pode armazenar instâncias de classes individuais como itens na tabela. Na definição de classe, a anotação `@DynamoDBHashKey` mapeia a propriedade `Id` para a chave primária. 

Por padrão, as propriedades da classe são mapeadas para os atributos com o mesmo nome na tabela. As propriedades `Title` e `ISBN` são mapeadas para os atributos com o mesmo nome na tabela. 

A anotação `@DynamoDBAttribute` é opcional quando o nome do atributo do DynamoDB corresponde ao nome da propriedade declarada na classe. Quando esses nomes são diferentes, use essa anotação com o parâmetro `attributeName` para especificar a qual atributo do DynamoDB essa propriedade corresponde. 

No exemplo anterior, a anotação `@DynamoDBAttribute` é adicionada a cada propriedade para garantir que os nomes de propriedades correspondam exatamente às tabelas criadas em uma etapa anterior e sejam consistentes com os nomes de atributos usados em outros exemplos de código neste guia. 

Sua definição de classe pode ter propriedades que não são mapeadas para atributos na tabela. Para identificar essas propriedades, adicione a anotação `@DynamoDBIgnore`. No exemplo anterior, a propriedade `SomeProp` está marcada com a anotação `@DynamoDBIgnore`. Ao carregar uma instância `CatalogItem` na tabela, sua instância `DynamoDBMapper` não inclui a propriedade `SomeProp`. Além disso, o mapeador não retorna esse atributo quando você recupera um item da tabela. 

Depois de definir sua classe de mapeamento, é possível usar métodos `DynamoDBMapper` para gravar uma instância dessa classe em um item correspondente na tabela `Catalog`. O exemplo de código a seguir demonstra essa técnica.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();

DynamoDBMapper mapper = new DynamoDBMapper(client);

CatalogItem item = new CatalogItem();
item.setId(102);
item.setTitle("Book 102 Title");
item.setISBN("222-2222222222");
item.setBookAuthors(new HashSet<String>(Arrays.asList("Author 1", "Author 2")));
item.setSomeProp("Test");

mapper.save(item);
```

O exemplo de código a seguir mostra como recuperar o item e acessar alguns dos seus atributos.

```
CatalogItem partitionKey = new CatalogItem();

partitionKey.setId(102);
DynamoDBQueryExpression<CatalogItem> queryExpression = new DynamoDBQueryExpression<CatalogItem>()
    .withHashKeyValues(partitionKey);

List<CatalogItem> itemList = mapper.query(CatalogItem.class, queryExpression);

for (int i = 0; i < itemList.size(); i++) {
    System.out.println(itemList.get(i).getTitle());
    System.out.println(itemList.get(i).getBookAuthors());
}
```

`DynamoDBMapper`O oferece uma forma intuitiva e natural de trabalhar com dados do DynamoDB no Java. Ele também fornece uma série de recursos internos, como bloqueio otimista, transações ACID, valores de chave de partição e chave de classificação gerados automaticamente e versionamento de objetos.

# Classe DynamoDBMapper
<a name="DynamoDBMapper.Methods"></a>



A classe `DynamoDBMapper` é o ponto de entrada do Amazon DynamoDB. Ela dá acesso a um endpoint do DynamoDB e permite acessar seus dados em várias tabelas. Ela também permite realizar várias operações de criação, leitura, atualização e exclusão (CRUD) em itens e executar consultas e verificações em tabelas. Essa classe fornece os seguintes métodos para trabalhar com o DynamoDB.

Para acessar a documentação Javadoc correspondente, consulte [DynamoDBMapper](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) no *Referência da API do AWS SDK para Java*.

**Topics**
+ [save](#DynamoDBMapper.Methods.save)
+ [balanceamento](#DynamoDBMapper.Methods.load)
+ [excluir](#DynamoDBMapper.Methods.delete)
+ [consultar](#DynamoDBMapper.Methods.query)
+ [queryPage](#DynamoDBMapper.Methods.queryPage)
+ [scan](#DynamoDBMapper.Methods.scan)
+ [scanPage](#DynamoDBMapper.Methods.scanPage)
+ [parallelScan](#DynamoDBMapper.Methods.parallelScan)
+ [batchSave](#DynamoDBMapper.Methods.batchSave)
+ [batchLoad](#DynamoDBMapper.Methods.batchLoad)
+ [batchDelete](#DynamoDBMapper.Methods.batchDelete)
+ [batchWrite](#DynamoDBMapper.Methods.batchWrite)
+ [transactionWrite](#DynamoDBMapper.Methods.transactionWrite)
+ [transactionLoad](#DynamoDBMapper.Methods.transactionLoad)
+ [contagem](#DynamoDBMapper.Methods.count)
+ [generateCreateTableRequest](#DynamoDBMapper.Methods.generateCreateTableRequest)
+ [createS3Link](#DynamoDBMapper.Methods.createS3Link)
+ [getS3ClientCache](#DynamoDBMapper.Methods.getS3ClientCache)

## save
<a name="DynamoDBMapper.Methods.save"></a>

Salva o objeto especificado na tabela. O objeto que você deseja salvar é o único parâmetro necessário para esse método. É possível fornecer parâmetros de configuração opcionais usando o objeto `DynamoDBMapperConfig`. 

Se um item com a mesma chave primária não existir, esse método criará um novo item na tabela. Se existir um item com a mesma chave primária, ele atualizará o item existente. Se a chave de partição e a chave de classificação forem do tipo String e estiverem anotadas com `@DynamoDBAutoGeneratedKey`, elas receberão um identificador universal exclusivo (UUID) aleatório se não forem inicializadas. Campos de versão anotados com `@DynamoDBVersionAttribute` são incrementados em um. Além disso, se um campo de versão for atualizado ou se uma chave for gerada, o objeto transmitido será atualizado como resultado da operação. 

Por padrão, somente atributos correspondentes às propriedades de classe mapeadas são atualizados. Quaisquer atributos existentes em um item não são afetados. No entanto, se você especificar `SaveBehavior.CLOBBER`, poderá forçar o item a ser completamente substituído.

```
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder()
    .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER).build();
        
mapper.save(item, config);
```

Se o versionamento estiver habilitado, as versões dos itens no lado do servidor e no lado do cliente deverão corresponder. No entanto, a versão não precisará corresponder se a opção `SaveBehavior.CLOBBER` for usada. Para obter mais informações sobre versionamento, consulte [DynamoDB e bloqueio positivo com número de versão](DynamoDBMapper.OptimisticLocking.md).

## balanceamento
<a name="DynamoDBMapper.Methods.load"></a>

Recupera um item de uma tabela. É necessário fornecer a chave primária do item que você deseja recuperar. É possível fornecer parâmetros de configuração opcionais usando o objeto `DynamoDBMapperConfig`. Por exemplo, você pode solicitar opcionalmente leituras altamente consistentes para garantir que esse método recupere apenas os valores de itens mais recentes, como mostra a seguinte instrução Java. 

```
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder()
    .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT).build();

CatalogItem item = mapper.load(CatalogItem.class, item.getId(), config);
```

Por padrão, o DynamoDB retorna o item que possui valores finais consistentes. Para obter informações sobre o modelo de consistência eventual do DynamoDB, consulte [Consistência de leitura do DynamoDB](HowItWorks.ReadConsistency.md).

## excluir
<a name="DynamoDBMapper.Methods.delete"></a>

Exclui um item da tabela. Você deve transmitir uma instância do objeto da classe mapeada. 

Se o versionamento estiver habilitado, as versões dos itens no lado do servidor e no lado do cliente deverão corresponder. No entanto, a versão não precisará corresponder se a opção `SaveBehavior.CLOBBER` for usada. Para obter mais informações sobre versionamento, consulte [DynamoDB e bloqueio positivo com número de versão](DynamoDBMapper.OptimisticLocking.md). 

## consultar
<a name="DynamoDBMapper.Methods.query"></a>

Consulta uma tabela ou um índice secundário.

Vamos supor que você tenha uma tabela, `Reply`, que armazena as respostas de tópicos de fórum. Cada assunto de tópico pode ter 0 ou mais respostas. A chave primária da tabela `Reply` consiste nos campos `Id` e `ReplyDateTime`, em que `Id` é a chave de partição e `ReplyDateTime` é a chave de classificação da chave primária.

```
Reply ( Id, ReplyDateTime, ... )
```

Vamos supor que você tenha criado um mapeamento entre uma classe `Reply` e a tabela `Reply` correspondente no DynamoDB. O código Java a seguir usa `DynamoDBMapper` para localizar todas as respostas nas últimas duas semanas para um assunto de tópico específico.

**Example**  

```
String forumName = "&DDB;";
String forumSubject = "&DDB; Thread 1";
String partitionKey = forumName + "#" + forumSubject;

long twoWeeksAgoMilli = (new Date()).getTime() - (14L*24L*60L*60L*1000L);
Date twoWeeksAgo = new Date();
twoWeeksAgo.setTime(twoWeeksAgoMilli);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String twoWeeksAgoStr = df.format(twoWeeksAgo);

Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1", new AttributeValue().withS(partitionKey));
eav.put(":v2",new AttributeValue().withS(twoWeeksAgoStr.toString()));

DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>()
    .withKeyConditionExpression("Id = :v1 and ReplyDateTime > :v2")
    .withExpressionAttributeValues(eav);

List<Reply> latestReplies = mapper.query(Reply.class, queryExpression);
```

A consulta retorna uma coleção de objetos `Reply`. 

Por padrão, o método `query` retorna uma coleção de "carregamento preguiçoso". Ele inicialmente retorna apenas uma página de resultados e, em seguida, faz uma chamada de serviço para a próxima página, se necessário. Para obter todos os itens correspondentes, faça uma iteração na coleção `latestReplies`. 

Observe que chamar o método `size()` na coleção carregará todos os resultados para fornecer uma contagem precisa. Isso pode fazer com que uma grande quantidade de throughput provisionado seja consumida, e em uma tabela muito grande pode até esgotar toda a memória na JVM.

Para consultar um índice, você deve primeiro modelá-lo como uma classe de mapeador. Suponha que a tabela `Reply` tenha um índice global secundário chamado *PostedBy-Message-Index*. A chave de partição para esse índice é `PostedBy`, e a chave de classificação é `Message`. A definição de classe para um item no índice seria semelhante ao seguinte.

```
@DynamoDBTable(tableName="Reply")
public class PostedByMessage {
    private String postedBy;
    private String message;

    @DynamoDBIndexHashKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "PostedBy")
    public String getPostedBy() { return postedBy; }
    public void setPostedBy(String postedBy) { this.postedBy = postedBy; }

    @DynamoDBIndexRangeKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "Message")
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }

   // Additional properties go here.
}
```

A anotação `@DynamoDBTable` indica que esse índice está associado à tabela `Reply`. A anotação `@DynamoDBIndexHashKey` representa a chave de partição (*PostedBy*) do índice, enquanto `@DynamoDBIndexRangeKey` representa a chave de classificação (*Message*) do índice.

Agora, você pode usar `DynamoDBMapper` para consultar o índice, recuperando um subconjunto das mensagens que foram postadas por um usuário específico. Você não precisará especificar o nome do índice se não tiver mapeamentos conflitantes entre tabelas e índices e se os mapeamentos já tiverem sido feitos no mapeador. O mapeador vai inferir com base na chave primária e na chave de classificação. O código a seguir consulta um índice secundário global. Como um índice secundário global oferece suporte para leituras finais consistentes, mas não para leituras altamente consistentes, é necessário especificar `withConsistentRead(false)`.

```
HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1",  new AttributeValue().withS("User A"));
eav.put(":v2",  new AttributeValue().withS("DynamoDB"));

DynamoDBQueryExpression<PostedByMessage> queryExpression = new DynamoDBQueryExpression<PostedByMessage>()
    .withIndexName("PostedBy-Message-Index")
    .withConsistentRead(false)
    .withKeyConditionExpression("PostedBy = :v1 and begins_with(Message, :v2)")
    .withExpressionAttributeValues(eav);

List<PostedByMessage> iList =  mapper.query(PostedByMessage.class, queryExpression);
```

A consulta retorna uma coleção de objetos `PostedByMessage`.

## queryPage
<a name="DynamoDBMapper.Methods.queryPage"></a>

Consulta uma tabela ou um índice secundário e retorna uma única página de resultados correspondentes. Como acontece com o método `query`, você deve especificar um valor de chave de partição e um filtro de consulta que seja aplicado ao atributo de chave de classificação. No entanto, `queryPage` retorna somente a primeira "página" de dados, ou seja, a quantidade de dados que caberá em 1 MB 

## scan
<a name="DynamoDBMapper.Methods.scan"></a>

Verifica uma tabela ou um índice secundário inteiro. Você tem a opção de especificar uma `FilterExpression` para filtrar o conjunto de resultados.

Vamos supor que você tenha uma tabela, `Reply`, que armazena as respostas de tópicos de fórum. Cada assunto de tópico pode ter 0 ou mais respostas. A chave primária da tabela `Reply` consiste nos campos `Id` e `ReplyDateTime`, em que `Id` é a chave de partição e `ReplyDateTime` é a chave de classificação da chave primária.

```
Reply ( Id, ReplyDateTime, ... )
```

Se você mapeou uma classe Java para a tabela `Reply`, será possível usar `DynamoDBMapper` para verificar essa tabela. Por exemplo, o código Java a seguir verifica a tabela `Reply` inteira, retornando somente as respostas de um determinado ano.

**Example**  

```
HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":v1", new AttributeValue().withS("2015"));

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withFilterExpression("begins_with(ReplyDateTime,:v1)")
    .withExpressionAttributeValues(eav);

List<Reply> replies =  mapper.scan(Reply.class, scanExpression);
```

Por padrão, o método `scan` retorna uma coleção de "carregamento preguiçoso". Ele inicialmente retorna apenas uma página de resultados e, em seguida, faz uma chamada de serviço para a próxima página, se necessário. Para obter todos os itens correspondentes, faça uma iteração na coleção `replies`.

Observe que chamar o método `size()` na coleção carregará todos os resultados para fornecer uma contagem precisa. Isso pode fazer com que uma grande quantidade de throughput provisionado seja consumida, e em uma tabela muito grande pode até esgotar toda a memória na JVM.

Para verificar um índice, você deve primeiro modelá-lo como uma classe de mapeador. Suponha que a tabela `Reply` tenha um índice global secundário chamado `PostedBy-Message-Index`. A chave de partição para esse índice é `PostedBy`, e a chave de classificação é `Message`. Uma classe de mapeador para esse índice é mostrada na seção [consultar](#DynamoDBMapper.Methods.query). Ela usa as anotações `@DynamoDBIndexHashKey` e `@DynamoDBIndexRangeKey` para especificar a chave de classificação e a chave de partição do índice.

O código de exemplo a seguir verifica `PostedBy-Message-Index`. Ele não usa um filtro de verificação e, portanto, todos os itens no índice são retornados para você.

```
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withIndexName("PostedBy-Message-Index")
    .withConsistentRead(false);

    List<PostedByMessage> iList =  mapper.scan(PostedByMessage.class, scanExpression);
    Iterator<PostedByMessage> indexItems = iList.iterator();
```

## scanPage
<a name="DynamoDBMapper.Methods.scanPage"></a>

Verifica uma tabela ou um índice secundário e retorna uma única página de resultados correspondentes. Como com o método `scan`, você pode especificar opcionalmente um `FilterExpression` para filtrar o conjunto de resultados. No entanto, `scanPage` retorna somente a primeira “página” de dados, ou seja, a quantidade de dados que cabe em 1 MB.

## parallelScan
<a name="DynamoDBMapper.Methods.parallelScan"></a>

Realiza uma verificação paralela de uma tabela ou de um índice secundário inteiro. Você especifica um número de segmentos lógicos para a tabela, juntamente com uma expressão de verificação para filtrar os resultados. O `parallelScan` divide a tarefa de verificação entre vários operadores, um para cada segmento lógico. Por sua vez, esses operadores processam os dados em paralelo e retornam os resultados.

O exemplo de código Java a seguir realiza uma verificação paralela na tabela `Product`.

```
int numberOfThreads = 4;

Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":n", new AttributeValue().withN("100"));

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
    .withFilterExpression("Price <= :n")
    .withExpressionAttributeValues(eav);

List<Product> scanResult = mapper.parallelScan(Product.class, scanExpression, numberOfThreads);
```

## batchSave
<a name="DynamoDBMapper.Methods.batchSave"></a>

Salva os objetos em uma ou mais tabelas usando uma ou mais chamadas para o método `AmazonDynamoDB.batchWriteItem`. Esse método não fornece garantias de transação.

O código Java a seguir salva dois itens (livros) na tabela `ProductCatalog`.

```
Book book1 = new Book();
book1.setId(901);
book1.setProductCategory("Book");
book1.setTitle("Book 901 Title");

Book book2 = new Book();
book2.setId(902);
book2.setProductCategory("Book");
book2.setTitle("Book 902 Title");

mapper.batchSave(Arrays.asList(book1, book2));
```

## batchLoad
<a name="DynamoDBMapper.Methods.batchLoad"></a>

Recupera vários itens de uma ou mais tabelas usando suas chaves primárias.

O seguinte código Java recupera dois itens de duas tabelas diferentes.

```
ArrayList<Object> itemsToGet = new ArrayList<Object>();

ForumItem forumItem = new ForumItem();
forumItem.setForumName("Amazon DynamoDB");
itemsToGet.add(forumItem);

ThreadItem threadItem = new ThreadItem();
threadItem.setForumName("Amazon DynamoDB");
threadItem.setSubject("Amazon DynamoDB thread 1 message text");
itemsToGet.add(threadItem);

Map<String, List<Object>> items = mapper.batchLoad(itemsToGet);
```

## batchDelete
<a name="DynamoDBMapper.Methods.batchDelete"></a>

Exclui objetos de uma ou mais tabelas usando uma ou mais chamadas para o método `AmazonDynamoDB.batchWriteItem`. Esse método não fornece garantias de transação. 

O código Java a seguir exclui dois itens (livros) na tabela `ProductCatalog`.

```
Book book1 = mapper.load(Book.class, 901);
Book book2 = mapper.load(Book.class, 902);
mapper.batchDelete(Arrays.asList(book1, book2));
```

## batchWrite
<a name="DynamoDBMapper.Methods.batchWrite"></a>

Salva e exclui objetos em/de uma ou mais tabelas usando uma ou mais chamadas para o método `AmazonDynamoDB.batchWriteItem`. Esse método não oferece garantias de transação ou suporte para versionamento (inserções ou exclusões condicionais).

O código Java a seguir grava um novo item na tabela `Forum`, grava um novo item na tabela `Thread` e exclui um item da tabela `ProductCatalog`.

```
// Create a Forum item to save
Forum forumItem = new Forum();
forumItem.setName("Test BatchWrite Forum");

// Create a Thread item to save
Thread threadItem = new Thread();
threadItem.setForumName("AmazonDynamoDB");
threadItem.setSubject("My sample question");

// Load a ProductCatalog item to delete
Book book3 = mapper.load(Book.class, 903);

List<Object> objectsToWrite = Arrays.asList(forumItem, threadItem);
List<Book> objectsToDelete = Arrays.asList(book3);

mapper.batchWrite(objectsToWrite, objectsToDelete);
```

## transactionWrite
<a name="DynamoDBMapper.Methods.transactionWrite"></a>

Salva e exclui objetos em/de uma ou mais tabelas usando uma chamada para o método `AmazonDynamoDB.transactWriteItems`. 

Para obter uma lista de exceções específicas de transação, consulte [Erros TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html#API_TransactWriteItems_Errors). 

Para obter mais informações sobre transações do DynamoDB e as garantias de ACID (atomicidade, consistência, isolamento e durabilidade) fornecidas, consulte [Amazon DynamoDB Transactions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html). 

**nota**  
 Esse método não é compatível com o seguinte:  
[DynamoDBMapperConfig.SaveBehavior](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptionalConfig.html).

O código Java a seguir grava um novo item em cada uma das tabelas `Forum` e `Thread`, de forma transacional.

```
Thread s3ForumThread = new Thread();
s3ForumThread.setForumName("S3 Forum");
s3ForumThread.setSubject("Sample Subject 1");
s3ForumThread.setMessage("Sample Question 1");

Forum s3Forum = new Forum();
s3Forum.setName("S3 Forum");
s3Forum.setCategory("Amazon Web Services");
s3Forum.setThreads(1);

TransactionWriteRequest transactionWriteRequest = new TransactionWriteRequest();
transactionWriteRequest.addPut(s3Forum);
transactionWriteRequest.addPut(s3ForumThread);
mapper.transactionWrite(transactionWriteRequest);
```

## transactionLoad
<a name="DynamoDBMapper.Methods.transactionLoad"></a>

Carrega objetos de uma ou mais tabelas usando uma chamada para o método `AmazonDynamoDB.transactGetItems`. 

Para obter uma lista de exceções específicas de transação, consulte [Erros TransactGetItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html#API_TransactGetItems_Errors). 

Para obter mais informações sobre transações do DynamoDB e as garantias de ACID (atomicidade, consistência, isolamento e durabilidade) fornecidas, consulte [Amazon DynamoDB Transactions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html). 

O código Java a seguir carrega um item de cada uma das tabelas `Forum` e `Thread`, de forma transacional.

```
Forum dynamodbForum = new Forum();
dynamodbForum.setName("DynamoDB Forum");
Thread dynamodbForumThread = new Thread();
dynamodbForumThread.setForumName("DynamoDB Forum");

TransactionLoadRequest transactionLoadRequest = new TransactionLoadRequest();
transactionLoadRequest.addLoad(dynamodbForum);
transactionLoadRequest.addLoad(dynamodbForumThread);
mapper.transactionLoad(transactionLoadRequest);
```

## contagem
<a name="DynamoDBMapper.Methods.count"></a>

Avalia a expressão de verificação especificada e retorna a contagem de itens correspondentes. Dados de itens não são retornados.

## generateCreateTableRequest
<a name="DynamoDBMapper.Methods.generateCreateTableRequest"></a>

Analisa uma classe POJO que representa um tabela do DynamoDB e retorna um `CreateTableRequest` para essa tabela.

## createS3Link
<a name="DynamoDBMapper.Methods.createS3Link"></a>

Cria um link para um objeto no Amazon S3. Você deve especificar um nome de bucket e um nome de chave que identifique exclusivamente o objeto no bucket.

Para usar `createS3Link`, a sua classe de mapeador deve definir métodos getter e setter. O exemplo de código a seguir ilustra isso, adicionando um novo atributo e métodos getter/setter à classe `CatalogItem`:

```
@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {

    ...

    public S3Link productImage;

    ....

    @DynamoDBAttribute(attributeName = "ProductImage")
    public S3Link getProductImage() {
            return productImage;
    }

    public void setProductImage(S3Link productImage) {
        this.productImage = productImage;
    }

...
}
```

O código Java a seguir define um novo item a ser gravado na tabela `Product`. O item inclui um link para uma imagem do produto. Os dados da imagem são carregados no Amazon S3.

```
CatalogItem item = new CatalogItem();

item.setId(150);
item.setTitle("Book 150 Title");

String amzn-s3-demo-bucket = "amzn-s3-demo-bucket";
String myS3Key = "productImages/book_150_cover.jpg";
item.setProductImage(mapper.createS3Link(amzn-s3-demo-bucket, myS3Key));

item.getProductImage().uploadFrom(new File("/file/path/book_150_cover.jpg"));

mapper.save(item);
```

A classe `S3Link` fornece muitos outros métodos para manipular objetos no Amazon S3. Para obter mais informações, consulte os [Javadocs para `S3Link`](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/S3Link.html).

## getS3ClientCache
<a name="DynamoDBMapper.Methods.getS3ClientCache"></a>

Retorna o `S3ClientCache` subjacente para acessar o Amazon S3. Um `S3ClientCache` é um Mapa inteligente para objetos `AmazonS3Client`. Se você tem vários clientes, um `S3ClientCache` pode ajudá-lo a manter esses clientes organizados por região da AWS e pode criar novos clientes do Amazon S3 sob demanda.

# Tipos de dados compatíveis com DynamoDBMapper para Java
<a name="DynamoDBMapper.DataTypes"></a>

Esta seção descreve os tipos de dados arbitrários, as coleções e os tipos de dados Java primitivos com aceitos no Amazon DynamoDB. 

O Amazon DynamoDB oferece suporte aos seguintes tipos de dados Java primitivos e classes wrapper primitivas. 
+ `String`
+ `Boolean`, `boolean`
+ `Byte`, `byte`
+ `Date` (como a string de precisão em milissegundos [ISO\$18601](http://en.wikipedia.org/wiki/ISO_8601), modificada para UTC)
+ `Calendar` (como a string de precisão em milissegundos [ISO\$18601](http://en.wikipedia.org/wiki/ISO_8601), modificada para UTC)
+ `Long`, `long`
+ `Integer`, `int`
+ `Double`, `double`
+ `Float`, `float`
+ `BigDecimal`
+ `BigInteger`

**nota**  
Para obter mais informações sobre as regras de nomenclatura do DynamoDB e os vários tipos de dados compatíveis, consulte [Tipos de dados compatíveis e regras de nomenclatura no Amazon DynamoDB](HowItWorks.NamingRulesDataTypes.md). 
O DynamoDBMapper oferece suporte a valores Binary vazios.
Valores String vazios são compatíveis com o AWS SDK for Java 2.x.  
No AWS SDK para Java 1.x, o DynamoDBMapper oferece suporte à leitura de valores de atributos String vazios. No entanto, ele não gravará valores de atributos String vazios porque esses atributos são descartados da solicitação.

O DynamoDB oferece suporte aos tipos de coleção Java [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html), [List](http://docs.oracle.com/javase/6/docs/api/java/util/List.html) e [Map](http://docs.oracle.com/javase/6/docs/api/java/util/Map.html). A tabela a seguir resume como esses tipos Java são mapeados nos tipos do DynamoDB.


****  

| Tipo Java | Tipo do DynamoDB | 
| --- | --- | 
|  Todos os tipos de número  |  `N` (tipo Número)  | 
|  Strings  |  `S` (tipo String)   | 
|  Booleano  |  `BOOL` (tipo booliano), 0 ou 1.  | 
|  ByteBuffer  |  `B` (tipo Binário)  | 
|  Data  |  `S` (tipo String). Os valores de Date são armazenados como strings formatadas em ISO-8601.  | 
| Tipos de coleção [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html) |  Tipo `SS` (conjunto de strings), tipo `NS` (conjunto de números) e tipo `BS` (conjunto de binários).  | 

 A interface `DynamoDBTypeConverter` permite que você mapeie seus próprios tipos de dados arbitrários em um tipo de dados com suporte nativo do DynamoDB. Para obter mais informações, consulte [Mapear dados arbitrários no DynamoDB](DynamoDBMapper.ArbitraryDataMapping.md). 

# Anotações Java para DynamoDB
<a name="DynamoDBMapper.Annotations"></a>

Esta seção descreve as anotações que estão disponíveis para mapear suas classes e propriedades em tabelas e atributos no Amazon DynamoDB.

Para conhecer a documentação Javadoc correspondente, consulte [Resumo de tipos de anotação](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/package-summary.html) na [Referência da API do AWS SDK para Java](https://docs.aws.amazon.com/sdk-for-java/latest/reference/).

**nota**  
Nas seguintes anotações, apenas `DynamoDBTable` e `DynamoDBHashKey` são necessários. 

**Topics**
+ [DynamoDBAttribute](#DynamoDBMapper.Annotations.DynamoDBAttribute)
+ [DynamoDBAutoGeneratedKey](#DynamoDBMapper.Annotations.DynamoDBAutoGeneratedKey)
+ [DynamoDBAutoGeneratedTimestamp](#DynamoDBMapper.Annotations.DynamoDBAutoGeneratedTimestamp)
+ [DynamoDBDocument](#DynamoDBMapper.Annotations.DynamoDBDocument)
+ [DynamoDBHashKey](#DynamoDBMapper.Annotations.DynamoDBHashKey)
+ [DynamoDBIgnore](#DynamoDBMapper.Annotations.DynamoDBIgnore)
+ [DynamoDBIndexHashKey](#DynamoDBMapper.Annotations.DynamoDBIndexHashKey)
+ [DynamoDBIndexRangeKey](#DynamoDBMapper.Annotations.DynamoDBIndexRangeKey)
+ [DynamoDBRangeKey](#DynamoDBMapper.Annotations.DynamoDBRangeKey)
+ [DynamoDBTable](#DynamoDBMapper.Annotations.DynamoDBTable)
+ [DynamoDBTypeConverted](#DynamoDBMapper.Annotations.DynamoDBTypeConverted)
+ [DynamoDBTyped](#DynamoDBMapper.Annotations.DynamoDBTyped)
+ [DynamoDBVersionAttribute](#DynamoDBMapper.Annotations.DynamoDBVersionAttribute)

## DynamoDBAttribute
<a name="DynamoDBMapper.Annotations.DynamoDBAttribute"></a>

Mapeia uma propriedade para um atributo de tabela. Por padrão, cada propriedade de classe é mapeada para um atributo de item com o mesmo nome. No entanto, se os nomes não forem os mesmos, você poderá usar essa anotação para mapear uma propriedade para o atributo. No seguinte trecho de código Java, `DynamoDBAttribute` mapeia a propriedade `BookAuthors` para o nome de atributo `Authors` na tabela.

```
@DynamoDBAttribute(attributeName = "Authors")
public List<String> getBookAuthors() { return BookAuthors; }
public void setBookAuthors(List<String> BookAuthors) { this.BookAuthors = BookAuthors; }
```

O `DynamoDBMapper` usa `Authors` como o nome do atributo ao salvar o objeto na tabela. 

## DynamoDBAutoGeneratedKey
<a name="DynamoDBMapper.Annotations.DynamoDBAutoGeneratedKey"></a>

Marca uma propriedade de chave de partição ou de chave de classificação como sendo gerada automaticamente. `DynamoDBMapper` gera um [UUID](http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html) aleatório ao salvar esses atributos. Apenas propriedades String podem ser marcadas como chaves geradas automaticamente. 

O exemplo a seguir demonstra o uso de chaves geradas automaticamente.

```
@DynamoDBTable(tableName="AutoGeneratedKeysExample")
public class AutoGeneratedKeys {
    private String id;
    private String payload;

    @DynamoDBHashKey(attributeName = "Id")
    @DynamoDBAutoGeneratedKey
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    @DynamoDBAttribute(attributeName="payload")
    public String getPayload() { return this.payload; }
    public void setPayload(String payload) { this.payload = payload; }

    public static void saveItem() {
        AutoGeneratedKeys obj = new AutoGeneratedKeys();
        obj.setPayload("abc123");

        // id field is null at this point
        DynamoDBMapper mapper = new DynamoDBMapper(dynamoDBClient);
        mapper.save(obj);

        System.out.println("Object was saved with id " + obj.getId());
    }
}
```

## DynamoDBAutoGeneratedTimestamp
<a name="DynamoDBMapper.Annotations.DynamoDBAutoGeneratedTimestamp"></a>

Gera automaticamente um carimbo de data/hora.

```
@DynamoDBAutoGeneratedTimestamp(strategy=DynamoDBAutoGenerateStrategy.ALWAYS)
public Date getLastUpdatedDate() { return lastUpdatedDate; }
public void setLastUpdatedDate(Date lastUpdatedDate) { this.lastUpdatedDate = lastUpdatedDate; }
```

Opcionalmente, a estratégia de geração automática pode ser definida fornecendo um atributo de estratégia. O padrão é `ALWAYS`.

## DynamoDBDocument
<a name="DynamoDBMapper.Annotations.DynamoDBDocument"></a>

Indica que uma classe pode ser serializada como um documento do Amazon DynamoDB.

Por exemplo, vamos supor que você queria mapear um documento JSON em um atributo do DynamoDB do tipo Map (`M`). O exemplo de código a seguir define um item que contém um atributo aninhado (Pictures) do tipo Map.

```
public class ProductCatalogItem {

    private Integer id;  //partition key
    private Pictures pictures;
    /* ...other attributes omitted... */

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id;}
    public void setId(Integer id) {this.id = id;}

    @DynamoDBAttribute(attributeName="Pictures")
    public Pictures getPictures() { return pictures;}
    public void setPictures(Pictures pictures) {this.pictures = pictures;}

    // Additional properties go here.

    @DynamoDBDocument
    public static class Pictures {
        private String frontView;
        private String rearView;
        private String sideView;

        @DynamoDBAttribute(attributeName = "FrontView")
        public String getFrontView() { return frontView; }
        public void setFrontView(String frontView) { this.frontView = frontView; }

        @DynamoDBAttribute(attributeName = "RearView")
        public String getRearView() { return rearView; }
        public void setRearView(String rearView) { this.rearView = rearView; }

        @DynamoDBAttribute(attributeName = "SideView")
        public String getSideView() { return sideView; }
        public void setSideView(String sideView) { this.sideView = sideView; }

     }
}
```

É possível salvar um novo item `ProductCatalog`, com `Pictures`, conforme mostrado no exemplo a seguir.

```
ProductCatalogItem item = new ProductCatalogItem();

Pictures pix = new Pictures();
pix.setFrontView("http://example.com/products/123_front.jpg");
pix.setRearView("http://example.com/products/123_rear.jpg");
pix.setSideView("http://example.com/products/123_left_side.jpg");
item.setPictures(pix);

item.setId(123);

mapper.save(item);
```

O item de `ProductCatalog` resultante seria semelhante ao seguinte (no formato JSON).

```
{
  "Id" : 123
  "Pictures" : {
    "SideView" : "http://example.com/products/123_left_side.jpg",
    "RearView" : "http://example.com/products/123_rear.jpg",
    "FrontView" : "http://example.com/products/123_front.jpg"
  }
}
```

## DynamoDBHashKey
<a name="DynamoDBMapper.Annotations.DynamoDBHashKey"></a>

Mapeia uma propriedade de classe para a chave de partição da tabela. A propriedade deve ser uma string escalar, número ou tipos binários. A propriedade não pode ser um tipo de coleção. 

Vamos supor que você tenha uma tabela, `ProductCatalog`, com `Id` como chave primária. O código Java a seguir define uma classe `CatalogItem` e mapeia sua propriedade `Id` para a chave primária da tabela `ProductCatalog` usando a tag `@DynamoDBHashKey`.

```
@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {
    private Integer Id;
   @DynamoDBHashKey(attributeName="Id")
   public Integer getId() {
        return Id;
   }
   public void setId(Integer Id) {
        this.Id = Id;
   }
   // Additional properties go here.
}
```

## DynamoDBIgnore
<a name="DynamoDBMapper.Annotations.DynamoDBIgnore"></a>

Indica à instância de `DynamoDBMapper` que a propriedade associada deve ser ignorada. Quando salvar dados na tabela, o `DynamoDBMapper` não salva essa propriedade na tabela.

 Aplicado ao método getter ou ao campo de classe de uma propriedade não modelada. Se a anotação for aplicada diretamente ao campo de classe, o getter e o setter correspondentes deverão ser declarados na mesma classe. 

## DynamoDBIndexHashKey
<a name="DynamoDBMapper.Annotations.DynamoDBIndexHashKey"></a>

Mapeia uma propriedade de classe na chave de partição de um índice secundário global. A propriedade deve ser uma string escalar, número ou tipos binários. A propriedade não pode ser um tipo de coleção. 

Use essa anotação se você precisa realizar uma `Query` em um índice secundário global. É necessário especificar o nome de índice (`globalSecondaryIndexName`). Se o nome da propriedade da classe for diferente da chave de partição do índice, também será necessário especificar o nome desse atributo de índice (`attributeName`).

## DynamoDBIndexRangeKey
<a name="DynamoDBMapper.Annotations.DynamoDBIndexRangeKey"></a>

Mapeia uma propriedade de classe na chave de classificação de um índice secundário global ou índice secundário local. A propriedade deve ser uma string escalar, número ou tipos binários. A propriedade não pode ser um tipo de coleção. 

Use essa anotação se você precisa realizar uma `Query` em um índice secundário local ou índice secundário global e deseja refinar seus resultados usando a chave de classificação do índice. É necessário especificar o nome de índice (`globalSecondaryIndexName` ou `localSecondaryIndexName`). Se o nome da propriedade da classe for diferente da chave de classificação do índice, você também deve especificar o nome desse atributo de índice (`attributeName`).

## DynamoDBRangeKey
<a name="DynamoDBMapper.Annotations.DynamoDBRangeKey"></a>

Mapeia uma propriedade de classe para a chave de classificação da tabela. A propriedade deve ser uma string escalar, número ou tipos binários. Não pode ser um tipo de coleção. 

Se a chave primária for composta (chave de partição e chave de classificação), você poderá usar essa tag para mapear seu campo de classe para a chave de classificação. Por exemplo, vamos supor que você tenha uma tabela `Reply` que armazena respostas para tópicos de fórum. Cada tópico pode ter muitas respostas. Portanto, a chave primária dessa tabela é tanto `ThreadId` quanto `ReplyDateTime`. `ThreadId` é a chave de partição, e `ReplyDateTime` é a chave de classificação. 

O código Java a seguir define uma classe `Reply` e a mapeia para a tabela `Reply`. Ele usa ambas as tags `@DynamoDBHashKey` e `@DynamoDBRangeKey` para identificar propriedades de classes que são mapeadas para a chave primária.

```
@DynamoDBTable(tableName="Reply")
public class Reply {
    private Integer id;
    private String replyDateTime;

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }

    @DynamoDBRangeKey(attributeName="ReplyDateTime")
    public String getReplyDateTime() { return replyDateTime; }
    public void setReplyDateTime(String replyDateTime) { this.replyDateTime = replyDateTime; }

   // Additional properties go here.
}
```

## DynamoDBTable
<a name="DynamoDBMapper.Annotations.DynamoDBTable"></a>

Identifica a tabela de destino no DynamoDB. Por exemplo, o seguinte código Java define uma classe `Developer` e a mapeia na tabela `People` no DynamoDB. 

```
@DynamoDBTable(tableName="People")
public class Developer { ...}
```

A anotação `@DynamoDBTable` pode ser herdada. Qualquer nova classe que herde da classe `Developer` também é mapeada para a tabela `People`. Por exemplo, suponha que você crie uma classe `Lead` que herde da classe `Developer`. Como você mapeou a classe `Developer` para a tabela `People`, e os objetos de classe `Lead` também são armazenados na mesma tabela.

Também é possível substituir `@DynamoDBTable`. Qualquer nova classe que herde da classe `Developer` por padrão é mapeada para a mesma tabela `People`. No entanto, você pode substituir esse mapeamento padrão. Por exemplo, se você criar uma classe que herda da classe `Developer`, será possível mapeá-la explicitamente para outra tabela adicionando a anotação `@DynamoDBTable`, conforme mostrado no seguinte exemplo de código Java.

```
@DynamoDBTable(tableName="Managers")
public class Manager extends Developer { ...}
```

## DynamoDBTypeConverted
<a name="DynamoDBMapper.Annotations.DynamoDBTypeConverted"></a>

Uma anotação para marcar uma propriedade como usando um conversor de tipo personalizado. Pode ser anotada em uma anotação definida pelo usuário para transmitir propriedades adicionais a `DynamoDBTypeConverter`. 

 A interface `DynamoDBTypeConverter` permite que você mapeie seus próprios tipos de dados arbitrários em um tipo de dados com suporte nativo do DynamoDB. Para obter mais informações, consulte [Mapear dados arbitrários no DynamoDB](DynamoDBMapper.ArbitraryDataMapping.md).

## DynamoDBTyped
<a name="DynamoDBMapper.Annotations.DynamoDBTyped"></a>

Uma anotação para substituir a associação de tipo de atributo padrão. Tipos padrão não exigem a anotação se estiverem aplicando a associação de atributo padrão para esse tipo. 

## DynamoDBVersionAttribute
<a name="DynamoDBMapper.Annotations.DynamoDBVersionAttribute"></a>

Identifica uma propriedade de classe para armazenar um número de versão de bloqueio otimista. `DynamoDBMapper` atribui um número de versão a essa propriedade ao salvar um novo item e o incrementa cada vez que você atualizar o item. Apenas há suporte para tipos de números escalares. Para obter informações sobre tipos de dados, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes). Para obter mais informações sobre versionamento, consulte [DynamoDB e bloqueio positivo com número de versão](DynamoDBMapper.OptimisticLocking.md).

# Definições de configuração opcionais para DynamoDBMapper
<a name="DynamoDBMapper.OptionalConfig"></a>

Quando você cria uma instância de `DynamoDBMapper`, ela tem certos comportamentos padrão que podem ser substituídos com o uso da classe `DynamoDBMapperConfig`. 

O seguinte trecho de código cria um `DynamoDBMapper` com configurações personalizadas:

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();

DynamoDBMapperConfig mapperConfig = DynamoDBMapperConfig.builder()
        .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER)
        .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT)
        .withTableNameOverride(null)
        .withPaginationLoadingStrategy(DynamoDBMapperConfig.PaginationLoadingStrategy.EAGER_LOADING)
    .build();

DynamoDBMapper mapper = new DynamoDBMapper(client, mapperConfig);
```

Para obter mais informações, consulte [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.html) na [Referência da API do AWS SDK para Java](https://docs.aws.amazon.com/sdk-for-java/latest/reference/).

Como alternativa, você pode usar os seguintes argumentos para uma instância de `DynamoDBMapperConfig`:
+ Um valor de enumeração `DynamoDBMapperConfig.ConsistentReads`:
  + `EVENTUAL`: a instância de mapeador usa uma solicitação de leitura eventualmente consistente.
  + `CONSISTENT`: a instância do mapeador usa uma solicitação de leitura fortemente consistente. É possível usar essa configuração opcional com operações `load`, `query` ou `scan`. Leituras altamente consistentes têm implicações sobre a performance e a cobrança. Consulte a [página de detalhes do produto](https://aws.amazon.com/dynamodb) do DynamoDB para obter mais informações.

  Se você não especificar uma configuração de consistência de leitura para sua instância de mapeador, o padrão será `EVENTUAL`.
**nota**  
Esse valor é aplicado em operações `query`, `querypage`, `load` e `batch load` do DynamoDBMapper.
+ Um valor de enumeração `DynamoDBMapperConfig.PaginationLoadingStrategy`: controla como a instância de mapeador processa uma lista paginada de dados, como os resultados de um `query` ou `scan`:
  + `LAZY_LOADING`: a instância do mapeador carrega dados quando possível e mantém todos os resultados carregados na memória.
  + `EAGER_LOADING`: a instância de mapeador carrega os dados assim que a lista é inicializada.
  + `ITERATION_ONLY`: você só pode usar um iterador para ler da lista. Durante a iteração, a lista limpará todos os resultados anteriores antes de carregar a próxima página e, portanto, ela manterá no máximo uma página dos resultados carregados na memória. Isso também significa que a lista só pode ser iterada uma vez. Essa estratégia é recomendada ao lidar com itens grandes, a fim de reduzir a sobrecarga de memória.

  Se você não especificar uma estratégia de carregamento de paginação para a sua instância de mapeador, o padrão será `LAZY_LOADING`.
+ Um valor de enumeração `DynamoDBMapperConfig.SaveBehavior`: especifica como a instância de mapeador deve lidar com atributos durante operações de salvamento:
  + `UPDATE`: durante uma operação de gravação, todos os atributos modelados são atualizados, enquanto os atributos não modelados não são afetados. Tipos de números primitivos (byte, int, long) são definidos como 0. Tipos de objetos são definidos como nulos. 
  + `CLOBBER`: limpa e substitui todos os atributos, incluindo os não modelados, durante uma operação de gravação. Isso é feito excluindo-se o item e o recriando. Restrições de campo com versionamento também são desconsideradas.

   Se você não especificar o comportamento de salvamento para sua instância de mapeador, o padrão será `UPDATE`.
**nota**  
As operações transacionais do DynamoDBMapper não são compatíveis com a enumeração do `DynamoDBMapperConfig.SaveBehavior`. 
+ Um objeto `DynamoDBMapperConfig.TableNameOverride` instrui a instância do mapeador a ignorar o nome de tabela especificado pela anotação `DynamoDBTable` de uma classe e, em vez disso, usar um nome de tabela diferente que você fornece. Isso é útil ao particionar dados em várias tabelas no tempo de execução. 

Você pode substituir o objeto de configuração padrão para `DynamoDBMapper` por operação, conforme necessário.

# DynamoDB e bloqueio positivo com número de versão
<a name="DynamoDBMapper.OptimisticLocking"></a>

O *bloqueio positivo * é uma estratégia para garantir que o item no lado do cliente que você está atualizando (ou excluindo) seja o mesmo que o item no Amazon DynamoDB. Se você usar essa estratégia, suas gravações de banco de dados serão protegidas contra substituição pelas gravações de outros e vice-versa.

Com o bloqueio positivo, cada item tem um atributo que serve como um número de versão. Se você recuperar um item de uma tabela, o aplicativo registrará o número da versão desse item. Você poderá atualizar o item somente se o número de versão no lado do servidor não tiver sido alterado. Se há uma incompatibilidade de versão, isso significa que alguém modificou o item antes de você. A tentativa de atualização falha, porque você tem uma versão obsoleta do item. Se isso acontecer, basta tentar novamente ao recuperar o item e tentar atualizá-lo. O bloqueio positivo impede que você substitua acidentalmente as alterações que foram feitas por outros. Também impede que outros substituam acidentalmente suas alterações.

Embora seja possível implementar a própria estratégia de bloqueio positivo, o AWS SDK para Java oferece a anotação `@DynamoDBVersionAttribute`. Na classe de mapeamento da sua tabela, você designa uma propriedade para armazenar o número da versão e a marca usando essa anotação. Quando um objeto é salvo, o item correspondente na tabela do DynamoDB terá um atributo que armazena o número da versão. O `DynamoDBMapper` atribui um número de versão quando você salvar o objeto pela primeira vez e incrementa automaticamente o número da versão sempre que você atualiza o item. Suas solicitações de atualização ou exclusão só serão bem-sucedidas se a versão do objeto no lado do cliente corresponder ao número de versão correspondente do item na tabela do DynamoDB.

 `ConditionalCheckFailedException` será lançada se: 
+  Você usar bloqueio positivo com `@DynamoDBVersionAttribute` e o valor de versão no servidor for diferente do valor no lado do cliente. 
+  Você especificar suas próprias restrições condicionais ao salvar dados usando `DynamoDBMapper` com `DynamoDBSaveExpression` e ocorrer falha nessas restrições. 

**nota**  
As tabelas globais do DynamoDB usam uma reconciliação “último gravador ganha” entre as atualizações simultâneas. Se você usa tabelas globais, a política de último gravador ganha. Portanto, neste caso, a estratégia de bloqueio não funciona como esperado.
As operações de gravação transacional `DynamoDBMapper` não são compatíveis com expressões de condição e anotação `@DynamoDBVersionAttribute` no mesmo objeto. Se um objeto em uma gravação transacional for anotado com `@DynamoDBVersionAttribute` e também tiver uma expressão de condição, a SdkClientException será lançada.

Por exemplo, o código Java a seguir define uma classe `CatalogItem` que tem várias propriedades. A propriedade `Version` está marcada com a anotação `@DynamoDBVersionAttribute`.

**Example**  

```
@DynamoDBTable(tableName="ProductCatalog")
public class CatalogItem {

    private Integer id;
    private String title;
    private String ISBN;
    private Set<String> bookAuthors;
    private String someProp;
    private Long version;

    @DynamoDBHashKey(attributeName="Id")
    public Integer getId() { return id; }
    public void setId(Integer Id) { this.id = Id; }

    @DynamoDBAttribute(attributeName="Title")
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }

    @DynamoDBAttribute(attributeName="ISBN")
    public String getISBN() { return ISBN; }
    public void setISBN(String ISBN) { this.ISBN = ISBN;}

    @DynamoDBAttribute(attributeName = "Authors")
    public Set<String> getBookAuthors() { return bookAuthors; }
    public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; }

    @DynamoDBIgnore
    public String getSomeProp() { return someProp;}
    public void setSomeProp(String someProp) {this.someProp = someProp;}

    @DynamoDBVersionAttribute
    public Long getVersion() { return version; }
    public void setVersion(Long version) { this.version = version;}
}
```

Você pode aplicar a anotação `@DynamoDBVersionAttribute` a tipos anuláveis fornecidos pelas classes wrapper primitivas que fornecem um tipo que permite valor nulo, como `Long` e `Integer`. 

O bloqueio positivo tem o seguinte impacto sobre estes métodos `DynamoDBMapper`:
+ `save`: para um novo item, `DynamoDBMapper` atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação de salvamento será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponderem. A classe `DynamoDBMapper` incrementa o número de versão automaticamente.
+ `delete`: o método `delete` usa um objeto como parâmetro, e `DynamoDBMapper` realiza uma verificação de versão antes de excluir o item. A verificação da versão pode ser desabilitada se `DynamoDBMapperConfig.SaveBehavior.CLOBBER` for especificado na solicitação.

  A implementação interna do bloqueio positivo em `DynamoDBMapper` usa o suporte a atualizações e exclusões condicionais fornecido pelo DynamoDB. 
+ `transactionWrite` —
  + `Put`: para um novo item, `DynamoDBMapper` atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação Put será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder. A classe `DynamoDBMapper` incrementa o número de versão automaticamente.
  + `Update`: para um novo item, `DynamoDBMapper` atribui um número de versão inicial 1. Se você recuperar um item, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação Update será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponder. A classe `DynamoDBMapper` incrementa o número de versão automaticamente.
  + `Delete`: o `DynamoDBMapper` realiza uma verificação de versão antes de excluir o item. A operação Delete só será bem-sucedida se o número de versão no lado do cliente e no lado do servidor corresponder.
  + `ConditionCheck`: a anotação `@DynamoDBVersionAttribute` não é compatível com operações `ConditionCheck`. Uma SdkClientException será lançada quando um item `ConditionCheck` for anotado com `@DynamoDBVersionAttribute`. 

## Desabilitar o bloqueio positivo
<a name="DynamoDBMapper.OptimisticLocking.Disabling"></a>

Para desabilitar o bloqueio positivo, você pode alterar o valor de enumeração `DynamoDBMapperConfig.SaveBehavior` de `UPDATE` para `CLOBBER`. Você pode fazer isso criando uma instância de `DynamoDBMapperConfig` que ignora a verificação de versão e usando essa instância para todas as suas solicitações. Para obter informações sobre `DynamoDBMapperConfig.SaveBehavior` e outros parâmetros `DynamoDBMapper` opcionais, consulte [Definições de configuração opcionais para DynamoDBMapper](DynamoDBMapper.OptionalConfig.md). 

Você também pode definir um comportamento de bloqueio somente para uma operação específica. Por exemplo, o seguinte trecho de código Java usa `DynamoDBMapper` para salvar um item de catálogo. Ele especifica `DynamoDBMapperConfig.SaveBehavior` adicionando o parâmetro `DynamoDBMapperConfig` opcional ao método `save`. 

**nota**  
O método transactionWrite não oferece suporte à configuração DynamoDBMapperConfig.SaveBehavior. A desabilitação do bloqueio positivo para transactionWrite é incompatível.

**Example**  

```
DynamoDBMapper mapper = new DynamoDBMapper(client);

// Load a catalog item.
CatalogItem item = mapper.load(CatalogItem.class, 101);
item.setTitle("This is a new title for the item");
...
// Save the item.
mapper.save(item,
    new DynamoDBMapperConfig(
        DynamoDBMapperConfig.SaveBehavior.CLOBBER));
```

# Mapear dados arbitrários no DynamoDB
<a name="DynamoDBMapper.ArbitraryDataMapping"></a>

Além dos tipos de Java compatíveis (consulte [Tipos de dados compatíveis com DynamoDBMapper para Java](DynamoDBMapper.DataTypes.md)), é possível usar tipos em sua aplicação para os quais não há um mapeamento direto para os tipos do Amazon DynamoDB. Para mapear esses tipos, é necessário fornecer uma implementação que converta o tipo complexo em um tipo compatível com o DynamoDB e vice-versa, e anotar o método de acesso de tipos complexos usando a anotação `@DynamoDBTypeConverted`. O código de conversor transforma os dados quando os objetos são salvos ou carregados. Ele também é usado para todas as operações que consomem tipos complexos. Observe que, ao comparar dados durante operações de consulta e verificação, as comparações são feitas com os dados armazenados no DynamoDB.

Por exemplo, considere a seguinte classe `CatalogItem`, que define uma propriedade, `Dimension`, que é de `DimensionType`. Essa propriedade armazena as dimensões de itens, como altura, largura e espessura. Suponha que você decida armazenar essas dimensões de itens como uma string (como 8.5x11x.05) no DynamoDB. O exemplo a seguir fornece o código de conversor que converte o objeto `DimensionType` em uma string e uma string em `DimensionType`.



**nota**  
Este exemplo de código pressupõe que você já carregou dados no DynamoDB para sua conta seguindo as instruções na seção [Criar tabelas e carregar dados para exemplos de código no DynamoDB](SampleData.md).  
Para obter instruções passo a passo sobre como executar o exemplo a seguir, consulte [Exemplos de código Java](CodeSamples.Java.md).

**Example**  

```
public class DynamoDBMapperExample {

    static AmazonDynamoDB client;

    public static void main(String[] args) throws IOException {

        // Set the AWS region you want to access.
        Regions usWest2 = Regions.US_WEST_2;
        client = AmazonDynamoDBClientBuilder.standard().withRegion(usWest2).build();

        DimensionType dimType = new DimensionType();
        dimType.setHeight("8.00");
        dimType.setLength("11.0");
        dimType.setThickness("1.0");

        Book book = new Book();
        book.setId(502);
        book.setTitle("Book 502");
        book.setISBN("555-5555555555");
        book.setBookAuthors(new HashSet<String>(Arrays.asList("Author1", "Author2")));
        book.setDimensions(dimType);

        DynamoDBMapper mapper = new DynamoDBMapper(client);
        mapper.save(book);

        Book bookRetrieved = mapper.load(Book.class, 502);
        System.out.println("Book info: " + "\n" + bookRetrieved);

        bookRetrieved.getDimensions().setHeight("9.0");
        bookRetrieved.getDimensions().setLength("12.0");
        bookRetrieved.getDimensions().setThickness("2.0");

        mapper.save(bookRetrieved);

        bookRetrieved = mapper.load(Book.class, 502);
        System.out.println("Updated book info: " + "\n" + bookRetrieved);
    }

    @DynamoDBTable(tableName = "ProductCatalog")
    public static class Book {
        private int id;
        private String title;
        private String ISBN;
        private Set<String> bookAuthors;
        private DimensionType dimensionType;

        // Partition key
        @DynamoDBHashKey(attributeName = "Id")
        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        @DynamoDBAttribute(attributeName = "Title")
        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        @DynamoDBAttribute(attributeName = "ISBN")
        public String getISBN() {
            return ISBN;
        }

        public void setISBN(String ISBN) {
            this.ISBN = ISBN;
        }

        @DynamoDBAttribute(attributeName = "Authors")
        public Set<String> getBookAuthors() {
            return bookAuthors;
        }

        public void setBookAuthors(Set<String> bookAuthors) {
            this.bookAuthors = bookAuthors;
        }

        @DynamoDBTypeConverted(converter = DimensionTypeConverter.class)
        @DynamoDBAttribute(attributeName = "Dimensions")
        public DimensionType getDimensions() {
            return dimensionType;
        }

        @DynamoDBAttribute(attributeName = "Dimensions")
        public void setDimensions(DimensionType dimensionType) {
            this.dimensionType = dimensionType;
        }

        @Override
        public String toString() {
            return "Book [ISBN=" + ISBN + ", bookAuthors=" + bookAuthors + ", dimensionType= "
                    + dimensionType.getHeight() + " X " + dimensionType.getLength() + " X "
                    + dimensionType.getThickness()
                    + ", Id=" + id + ", Title=" + title + "]";
        }
    }

    static public class DimensionType {

        private String length;
        private String height;
        private String thickness;

        public String getLength() {
            return length;
        }

        public void setLength(String length) {
            this.length = length;
        }

        public String getHeight() {
            return height;
        }

        public void setHeight(String height) {
            this.height = height;
        }

        public String getThickness() {
            return thickness;
        }

        public void setThickness(String thickness) {
            this.thickness = thickness;
        }
    }

    // Converts the complex type DimensionType to a string and vice-versa.
    static public class DimensionTypeConverter implements DynamoDBTypeConverter<String, DimensionType> {

        @Override
        public String convert(DimensionType object) {
            DimensionType itemDimensions = (DimensionType) object;
            String dimension = null;
            try {
                if (itemDimensions != null) {
                    dimension = String.format("%s x %s x %s", itemDimensions.getLength(), itemDimensions.getHeight(),
                            itemDimensions.getThickness());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return dimension;
        }

        @Override
        public DimensionType unconvert(String s) {

            DimensionType itemDimension = new DimensionType();
            try {
                if (s != null && s.length() != 0) {
                    String[] data = s.split("x");
                    itemDimension.setLength(data[0].trim());
                    itemDimension.setHeight(data[1].trim());
                    itemDimension.setThickness(data[2].trim());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return itemDimension;
        }
    }
}
```

# Exemplos de DynamoDBMapper
<a name="DynamoDBMapper.Examples"></a>

O AWS SDK para Java fornece uma classe `DynamoDBMapper`, permitindo mapear classes do lado do cliente para tabelas do DynamoDB. Para usar `DynamoDBMapper`, defina a relação entre os itens em uma tabela do DynamoDB e as instâncias de objeto correspondentes no seu código. A classe `DynamoDBMapper` permite que você realize várias operações de criação, leitura, atualização e exclusão (CRUD) em itens e execute consultas e verificações em tabelas.

Para saber mais sobre como usar `DynamoDBMapper`, consulte [DynamoDB Examples Using the AWS SDK for Java ](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-dynamodb.html) (Exemplos do DynamoDB usando o SDK para Java) no *Guia do desenvolvedor do AWS SDK para Java 1.x*. 

# Java 2.x: Cliente Aprimorado do DynamoDB
<a name="DynamoDBEnhanced"></a>

O Cliente Aprimorado do DynamoDB é uma biblioteca de alto nível que faz parte do AWS SDK para Java versão 2 (v2). Ele oferece uma maneira simples de mapear classes do lado do cliente para tabelas do DynamoDB. Basta definir as relações entre as tabelas e suas classes de modelo correspondentes no seu código. Depois que você definir essas relações, poderá executar intuitivamente várias operações de criação, leitura, atualização ou exclusão (CRUD) em tabelas ou itens do DynamoDB.

Para obter mais informações sobre como você pode usar o cliente aprimorado com o DynamoDB, consulte [Usar o Cliente Aprimorado do DynamoDB no AWS SDK para Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html). 

# Trabalhar com o modelo de documento do .NET no DynamoDB
<a name="DotNetSDKMidLevel"></a>

O AWS SDK para .NET fornece classes do modelo de documento para empacotar algumas das operações de baixo nível do Amazon DynamoDB, simplificando ainda mais sua codificação. No modelo de documento, as classes primárias são `Table` e `Document`. A classe `Table` fornece métodos de operação de dados, como `PutItem`, `GetItem` e `DeleteItem`. Ela também fornece os métodos `Query` e `Scan`. A classe `Document` representa um único item em uma tabela.

As classes do modelo de documento anteriores estão disponíveis no namespace `Amazon.DynamoDBv2.DocumentModel`.

**nota**  
Não é possível usar as classes do modelo de documento para criar, atualizar e excluir tabelas. Por outro lado, o modelo de documento oferece suporte à maioria das operações de dados comuns.

**Topics**
+ [Tipos de dados compatíveis](#MidLevelAPILimitations.SupportedTypes)

## Tipos de dados compatíveis
<a name="MidLevelAPILimitations.SupportedTypes"></a>

O modelo de documento oferece suporte a um conjunto de tipos de dados .NET primitivos e tipos de dados de coleções. O modelo é compatível com os seguintes tipos de dados primitivos. 
+ `bool`
+ `byte` 
+ `char`
+ `DateTime`
+ `decimal`
+ `double`
+ `float`
+ `Guid`
+ `Int16`
+ `Int32`
+ `Int64`
+ `SByte`
+ `string`
+ `UInt16`
+ `UInt32`
+ `UInt64`

A tabela a seguir resume o mapeamento dos tipos .NET anteriores nos tipos do DynamoDB.


****  

| Tipo primitivo .NET | Tipo do DynamoDB | 
| --- | --- | 
|  Todos os tipos de número  |  `N` (tipo Número)  | 
|  Todos os tipos de string  |  `S` (tipo String)   | 
|  MemoryStream, byte[]  |  `B` (tipo Binário)   | 
| bool | N (tipo numérico), 0 representa false 1 representa true. | 
| DateTime | S (tipo String). Os valores de DateTime são armazenados como strings formatadas em ISO-8601. | 
| Guid | S (tipo String). | 
| Tipos de coleção (List, HashSet e array) | Tipo BS (conjunto binário), tipo SS (conjunto de strings) e tipo NS (conjunto de números) | 

O AWS SDK para .NET define tipos para mapear os tipos Boolean, Null, List e Map do DynamoDB na API do modelo de documento do .NET:
+ Use `DynamoDBBool` para o tipo booliano.
+ Use `DynamoDBNull` para o tipo nulo.
+ Use `DynamoDBList` para o tipo lista.
+ Use `Document` para o tipo mapa.

**nota**  
Valores binários vazios são compatíveis.
A leitura de valores string vazios é compatível. Os valores de atributos string vazios são compatíveis nos valores de atributos do tipo de conjunto string durante a gravação no DynamoDB. Os valores de atributos string vazios do tipo string e os valores string vazios contidos no tipo Lista ou Mapa são descartados das solicitações de gravação

# Trabalhar com o modelo de persistência de objetos do .NET e o DynamoDB
<a name="DotNetSDKHighLevel"></a>

O AWS SDK para .NET fornece um modelo de persistência de objetos que permite mapear classes do cliente em tabelas do Amazon DynamoDB. Em seguida, cada instância de objeto é mapeada para um item nas tabelas correspondentes. Para salvar objetos no lado do cliente nas tabelas, o modelo de persistência de objetos fornece a classe `DynamoDBContext`, um ponto de entrada para o DynamoDB. Esta classe fornece uma conexão ao DynamoDB e permite que você acesse tabelas, execute várias operações CRUD e realize consultas.

O modelo de persistência de objetos fornece um conjunto de atributos para mapear classes no lado do cliente para tabelas e propriedades/campos para atributos de tabela.

**nota**  
O modelo de persistência de objetos não fornece uma API para criar, atualizar ou excluir tabelas. Ele fornece apenas operações de dados. É possível usar somente a API de baixo nível do AWS SDK para .NET para criar, atualizar e excluir tabelas.

O exemplo a seguir mostra como o modelo de persistência de objetos funciona. Ele começa com a tabela `ProductCatalog`. `Id` é a chave primária.

```
ProductCatalog(Id, ...)
```

Suponha que você tenha uma classe `Book` com propriedades `Title`, `ISBN` e `Authors`. É possível mapear a classe `Book` na tabela `ProductCatalog` adicionando os atributos definidos pelo modelo de persistência de objetos, conforme mostrado no trecho de código C\$1 a seguir.

**Example**  

```
[DynamoDBTable("ProductCatalog")]
  public class Book
  {
    [DynamoDBHashKey]
    public int Id { get; set; }

    public string Title { get; set; }
    public int ISBN { get; set; }

    [DynamoDBProperty("Authors")]
    public List<string> BookAuthors { get; set; }

    [DynamoDBIgnore]
    public string CoverPage { get; set; }
  }
```

No exemplo anterior, o atributo `DynamoDBTable` mapeia a classe `Book` na tabela `ProductCatalog`.

O modelo de persistência objeto oferece suporte a tipos de mapeamento explícito e padrão entre propriedades de classe e atributos de tabela.
+ **Mapeamento explícito**: para mapear uma propriedade em uma chave primária, você deve usar os atributos `DynamoDBHashKey` e `DynamoDBRangeKey` do modelo de persistência de objetos. Além disso, para os atributos de chave não primárias, se um nome de propriedade na sua classe e o atributo de tabela correspondente ao qual você deseja mapear não forem os mesmos, será necessário definir o mapeamento adicionando explicitamente o atributo `DynamoDBProperty`.

  No exemplo anterior, a propriedade `Id` é mapeada na chave primária com o mesmo nome, e a propriedade `BookAuthors` é mapeada no atributo `Authors` na tabela `ProductCatalog`.
+ **Mapeamento padrão — **por padrão, o modelo de persistência objeto mapeia as propriedades da classe para os atributos com o mesmo nome na tabela.

  No exemplo anterior, as propriedades `Title` e `ISBN` são mapeadas nos atributos com o mesmo nome na tabela `ProductCatalog`.

Não é necessário mapear cada propriedade de classe. Identifique essas propriedades adicionando o atributo `DynamoDBIgnore`. Quando você salva uma instância de `Book` na tabela, `DynamoDBContext` não inclui a propriedade `CoverPage`. Ele também não retorna essa propriedade quando você recupera a instância de livro.

É possível mapear propriedades de tipos primitivos do .NET, como int e string. Também é possível mapear qualquer tipo de dados arbitrário, desde que você forneça um conversor apropriado para mapear os dados arbitrários em um do tipos do DynamoDB. Para saber mais sobre o mapeamento de tipos arbitrários, consulte [Mapear dados arbitrários com o DynamoDB usando o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.ArbitraryDataMapping.md).

O modelo de persistência objetos oferece suporte a bloqueio otimista. Durante uma operação de atualização, isso garante que você tenha a cópia mais recente do item que está prestes a atualizar. Para obter mais informações, consulte [Bloqueio positivo usando o DynamoDB e o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.VersionSupport.md).

Para obter mais informações, consulte os tópicos abaixo:

**Topics**
+ [Tipos de dados compatíveis](#DotNetDynamoDBContext.SupportedTypes)
+ [Atributos do DynamoDB do modelo de persistência de objetos do .NET](DeclarativeTagsList.md)
+ [Classe DynamoDBContext do modelo de persistência de objetos do .NET](DotNetDynamoDBContext.md)
+ [Bloqueio positivo usando o DynamoDB e o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.VersionSupport.md)
+ [Mapear dados arbitrários com o DynamoDB usando o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.ArbitraryDataMapping.md)

## Tipos de dados compatíveis
<a name="DotNetDynamoDBContext.SupportedTypes"></a>

O modelo de persistência de objetos oferece suporte a um conjunto de tipos de dados primitivos do .NET, coleções e tipos de dados arbitrários. O modelo é compatível com os seguintes tipos de dados primitivos. 
+ `bool`
+ `byte` 
+ `char`
+ `DateTime`
+ `decimal`
+ `double`
+ `float`
+ `Int16`
+ `Int32`
+ `Int64`
+ `SByte`
+ `string`
+ `UInt16`
+ `UInt32`
+ `UInt64`

O modelo de persistência de objetos também oferece suporte aos tipos de coleção .NET. `DynamoDBContext` é capaz de converter tipos de coleção concretos e objetos CLR básicos (POCOs).

A tabela a seguir resume o mapeamento dos tipos .NET anteriores nos tipos do DynamoDB.


****  

| Tipo primitivo .NET | Tipo do DynamoDB | 
| --- | --- | 
|  Todos os tipos de número  |  `N` (tipo Número)  | 
|  Todos os tipos de string  |  `S` (tipo String)   | 
|  MemoryStream, byte[]  |  `B` (tipo Binário)   | 
| bool | N (tipo numérico), 0 representa false 1 representa true. | 
| Tipos de coleção | Tipo BS (conjunto binário), tipo SS (conjunto de strings) e tipo NS (conjunto de números) | 
| DateTime | S (tipo String). Os valores de DateTime são armazenados como strings formatadas em ISO-8601. | 

O modelo de persistência de objetos também oferece suporte a tipos de dados arbitrários. No entanto, você deve fornecer o código de conversor para mapear os tipos complexos em tipos do DynamoDB.

**nota**  
Valores binários vazios são compatíveis.
A leitura de valores string vazios é compatível. Os valores de atributos string vazios são compatíveis nos valores de atributos do tipo de conjunto string durante a gravação no DynamoDB. Os valores de atributos string vazios do tipo string e os valores string vazios contidos no tipo Lista ou Mapa são descartados das solicitações de gravação

# Atributos do DynamoDB do modelo de persistência de objetos do .NET
<a name="DeclarativeTagsList"></a>

Esta seção descreve os atributos oferecidos pelo modelo de persistência objetos para que você possa mapear suas classes e propriedades em tabelas e atributos do DynamoDB.

**nota**  
Nos seguintes atributos, apenas `DynamoDBTable` e `DynamoDBHashKey` são necessários.

## DynamoDBGlobalSecondaryIndexHashKey
<a name="w2aac17b9c21c23c37b7"></a>

Mapeia uma propriedade de classe na chave de partição de um índice secundário global. Use esse atributo se você precisa realizar uma `Query` em um índice secundário global.

## DynamoDBGlobalSecondaryIndexRangeKey
<a name="w2aac17b9c21c23c37b9"></a>

Mapeia uma propriedade de classe na chave de classificação de um índice secundário global. Use esse atributo se você precisa realizar uma operação `Query` em um índice secundário global e deseja refinar seus resultados usando a chave de classificação de índice.

## DynamoDBHashKey
<a name="w2aac17b9c21c23c37c11"></a>

Mapeia uma propriedade de classe para a chave de partição da chave primária da tabela. Os atributos de chave primária não podem ser um tipo de coleção.

Os seguintes exemplos de código C\$1 mapeiam a classe `Book` na tabela `ProductCatalog` e a propriedade `Id` na chave de partição da chave primária da tabela.

```
[DynamoDBTable("ProductCatalog")]
public class Book 
{
    [DynamoDBHashKey]
    public int Id { get; set; }

    // Additional properties go here.
}
```

## DynamoDBIgnore
<a name="w2aac17b9c21c23c37c13"></a>

Indica que a propriedade associada deve ser ignorada. Se não desejar salvar nenhuma das suas propriedades de classe, você poderá adicionar esse atributo para instruir `DynamoDBContext` a não incluir essa propriedade ao salvar objetos na tabela.

## DynamoDBLocalSecondaryIndexRangeKey
<a name="w2aac17b9c21c23c37c15"></a>

Mapeia uma propriedade de classe na chave de classificação de um índice secundário local. Use esse atributo se você precisa realizar uma operação `Query` em um índice secundário local e deseja refinar seus resultados usando a chave de classificação de índice.

## DynamoDBProperty
<a name="w2aac17b9c21c23c37c17"></a>

Mapeia uma propriedade de classe em um atributo de tabela. Se a propriedade de classe for mapeada em um atributo de tabela com o mesmo nome, não será necessário especificar esse atributo. No entanto, se os nomes não forem iguais, você poderá usar essa tag para fornecer o mapeamento. Na instrução C\$1 a seguir, `DynamoDBProperty` mapeia a propriedade `BookAuthors` no atributo `Authors` na tabela. 

```
[DynamoDBProperty("Authors")]
public List<string> BookAuthors { get; set; }
```

`DynamoDBContext` usa essas informações de mapeamento para criar o atributo `Authors` ao salvar dados de objetos na tabela correspondente.

## DynamoDBRenamable
<a name="w2aac17b9c21c23c37c19"></a>

Especifica um nome alternativo para uma propriedade de classe. Isso é útil quando você está escrevendo um conversor personalizado para o mapeamento de dados arbitrários em uma tabela do DynamoDB na qual o nome de uma propriedade de classe é diferente de um atributo da tabela.

## DynamoDBRangeKey
<a name="w2aac17b9c21c23c37c21"></a>

Mapeia uma propriedade de classe na chave de classificação da chave primária da tabela. Se a tabela tiver uma chave primária composta (chave de partição e chave de classificação), você deverá especificar os atributos `DynamoDBHashKey` e `DynamoDBRangeKey` no seu mapeamento de classes.

Por exemplo, a tabela de exemplo `Reply` tem uma chave primária composta pela chave de partição `Id` e pela chave de classificação `Replenishment`. O exemplo de código C\$1 a seguir mapeia a classe `Reply` na tabela `Reply`. A definição de classe também indica que duas de suas propriedades são mapeadas para a chave primária.

```
[DynamoDBTable("Reply")]
public class Reply 
{
   [DynamoDBHashKey]
   public int ThreadId { get; set; }
   [DynamoDBRangeKey]
   public string Replenishment { get; set; }
   
   // Additional properties go here.
}
```

## DynamoDBTable
<a name="w2aac17b9c21c23c37c23"></a>

Identifica a tabela de destino do DynamoDB na qual a classe é mapeada. Por exemplo, o exemplo de código C\$1 a seguir mapeia a classe `Developer` na tabela `People` no DynamoDB.

```
[DynamoDBTable("People")]
public class Developer { ...}
```

Esse atributo pode ser herdado ou substituído.
+ O atributo `DynamoDBTable` pode ser herdado. No exemplo anterior, se você adicionar uma nova classe, `Lead`, que herda da classe `Developer`, ela também será mapeada na tabela `People`. Ambos os objetos `Developer` e `Lead` são armazenados na tabela `People`.
+ O atributo `DynamoDBTable` também pode ser sobrescrito. No exemplo de código C\$1 a seguir, a classe `Manager` herda da classe `Developer`. No entanto, a adição explícita do atributo `DynamoDBTable` mapeia a classe em outra tabela (`Managers`).

  ```
  [DynamoDBTable("Managers")]
  public class Manager : Developer { ...}
  ```

 É possível adicionar o parâmetro opcional, `LowerCamelCaseProperties`, para solicitar que o DynamoDB coloque em minúscula a primeira letra do nome da propriedade ao armazenar os objetos em uma tabela, conforme mostrado no exemplo de código C\$1 a seguir.

```
[DynamoDBTable("People", LowerCamelCaseProperties=true)]
public class Developer 
{
    string DeveloperName;
    ...
}
```

Ao salvar as instâncias da classe `Developer`, `DynamoDBContext` salva a propriedade `DeveloperName` como `developerName`.

## DynamoDBVersion
<a name="w2aac17b9c21c23c37c25"></a>

Identifica uma propriedade de classe para armazenar o número de versão do item. Para obter mais informações sobre versionamento, consulte [Bloqueio positivo usando o DynamoDB e o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.VersionSupport.md).

# Classe DynamoDBContext do modelo de persistência de objetos do .NET
<a name="DotNetDynamoDBContext"></a>

A classe `DynamoDBContext` é o ponto de entrada para do banco de dados do Amazon DynamoDB. Ela fornece uma conexão com o DynamoDB e permite que você acesse seus dados em várias tabelas, realize várias operações CRUD e execute consultas. A classe `DynamoDBContext` fornece os seguintes métodos:

**Topics**
+ [Create​MultiTable​BatchGet](#w2aac17b9c21c23c39b7)
+ [Create​MultiTable​BatchWrite](#w2aac17b9c21c23c39b9)
+ [CreateBatchGet](#w2aac17b9c21c23c39c11)
+ [CreateBatchWrite](#w2aac17b9c21c23c39c13)
+ [Excluir](#w2aac17b9c21c23c39c15)
+ [Descartar](#w2aac17b9c21c23c39c17)
+ [Execute​Batch​Get](#w2aac17b9c21c23c39c19)
+ [Execute​Batch​Write](#w2aac17b9c21c23c39c21)
+ [FromDocument](#w2aac17b9c21c23c39c23)
+ [FromQuery](#w2aac17b9c21c23c39c25)
+ [FromScan](#w2aac17b9c21c23c39c27)
+ [Get​Target​Table](#w2aac17b9c21c23c39c29)
+ [Carregar](#w2aac17b9c21c23c39c31)
+ [Consulta](#w2aac17b9c21c23c39c33)
+ [Save (Salvar)](#w2aac17b9c21c23c39c35)
+ [Verificar](#w2aac17b9c21c23c39c37)
+ [ToDocument](#w2aac17b9c21c23c39c39)
+ [Especificar parâmetros opcionais para DynamoDBContext](#OptionalConfigParams)

## Create​MultiTable​BatchGet
<a name="w2aac17b9c21c23c39b7"></a>

Cria um objeto `MultiTableBatchGet` formado por vários objetos `BatchGet` individuais. Cada um desses objetos `BatchGet` pode ser usado para recuperar itens de uma única tabela do DynamoDB.

Para recuperar os itens das tabelas, use o método `ExecuteBatchGet`, passando o objeto `MultiTableBatchGet` como um parâmetro.

## Create​MultiTable​BatchWrite
<a name="w2aac17b9c21c23c39b9"></a>

Cria um objeto `MultiTableBatchWrite` formado por vários objetos `BatchWrite` individuais. Cada um desses objetos `BatchWrite` pode ser usado para gravar ou excluir itens em uma única tabela do DynamoDB.

Para gravar nas tabelas, use o método `ExecuteBatchWrite`, passando o objeto `MultiTableBatchWrite` como um parâmetro.

## CreateBatchGet
<a name="w2aac17b9c21c23c39c11"></a>

Cria um objeto `BatchGet` que você pode usar para recuperar vários itens de uma tabela. 

## CreateBatchWrite
<a name="w2aac17b9c21c23c39c13"></a>

Cria um objeto `BatchWrite` que você pode usar para inserir vários itens em uma tabela ou para excluir vários itens de uma tabela. 

## Excluir
<a name="w2aac17b9c21c23c39c15"></a>

Exclui um item da tabela. O método requer a chave primária do item que você deseja excluir. É possível fornecer o valor da chave primária ou um objeto no lado do cliente que contém um valor de chave primária como um parâmetro para esse método.
+ Se você especificar um objeto no lado do cliente como um parâmetro e tiver habilitado o bloqueio otimista, a exclusão apenas será bem-sucedida se as versões no lado do cliente e no lado do servidor desse objeto corresponderem.
+ Se você especificar somente o valor da chave primária como parâmetro, a exclusão será bem-sucedida, independentemente de você ter habilitado ou não o bloqueio otimista.

**nota**  
Para realizar essa operação em segundo plano, use o método `DeleteAsync` em vez disso.

## Descartar
<a name="w2aac17b9c21c23c39c17"></a>

Descarta todos os recursos gerenciados e não gerenciados.

## Execute​Batch​Get
<a name="w2aac17b9c21c23c39c19"></a>

Lê dados de uma ou mais tabelas, processando todos os objetos `BatchGet` em um `MultiTableBatchGet`.

**nota**  
Para realizar essa operação em segundo plano, use o método `ExecuteBatchGetAsync` em vez disso.

## Execute​Batch​Write
<a name="w2aac17b9c21c23c39c21"></a>

Grava ou exclui dados em uma ou mais tabelas, processando todos os objetos `BatchWrite` em um `MultiTableBatchWrite`.

**nota**  
Para realizar essa operação em segundo plano, use o método `ExecuteBatchWriteAsync` em vez disso.

## FromDocument
<a name="w2aac17b9c21c23c39c23"></a>

Considerando uma instância de `Document`, o método `FromDocument` retorna uma instância de uma classe no lado do cliente.

Isso será útil se você quiser usar as classes de modelo de documento junto com o modelo de persistência de objetos para realizar qualquer operação de dados. Para obter mais informações sobre as classes do modelo de documento fornecidas pelo AWS SDK para .NET, consulte [Trabalhar com o modelo de documento do .NET no DynamoDB](DotNetSDKMidLevel.md).

Suponha que você tenha um objeto `Document` denominado `doc` que contém uma representação de um item `Forum`. (Para ver como construir esse objeto, consulte a descrição do método `ToDocument` mais adiante neste tópico.) Você pode usar `FromDocument` para recuperar o item `Forum` de `Document`, conforme mostrado no exemplo de código C\$1 a seguir.

**Example**  

```
forum101 = context.FromDocument<Forum>(101);
```

**nota**  
Se o objeto `Document` implementar a interface `IEnumerable`, você poderá usar o método `FromDocuments` em vez disso. Isso permite uma iteração sobre todas as instâncias da classe em `Document`.

## FromQuery
<a name="w2aac17b9c21c23c39c25"></a>

Executa uma operação `Query`, com os parâmetros de consulta definidos em um objeto `QueryOperationConfig`.

**nota**  
Para realizar essa operação em segundo plano, use o método `FromQueryAsync` em vez disso.

## FromScan
<a name="w2aac17b9c21c23c39c27"></a>

Executa uma operação `Scan`, com os parâmetros de verificação definidos em um objeto `ScanOperationConfig`.

**nota**  
Para realizar essa operação em segundo plano, use o método `FromScanAsync` em vez disso.

## Get​Target​Table
<a name="w2aac17b9c21c23c39c29"></a>

Recupera a tabela de destino para o tipo especificado. Isso é útil quando você está escrevendo um conversor personalizado para o mapeamento de dados arbitrários para uma tabela do DynamoDB e precisa determinar qual tabela está associada a um tipo de dados personalizado.

## Carregar
<a name="w2aac17b9c21c23c39c31"></a>

Recupera um item de uma tabela. O método requer somente a chave primária do item que você deseja recuperar. 

Por padrão, o DynamoDB retorna o item com valores finais consistentes. Para obter informações sobre o modelo final consistente, consulte [Consistência de leitura do DynamoDB](HowItWorks.ReadConsistency.md).

O método `Load` ou `LoadAsync` chama a operação [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html), que exige que você especifique a chave primária para a tabela. Como `GetItem` ignora o parâmetro `IndexName`, você não pode carregar um item usando a partição ou a chave de classificação de um índice. Portanto, é necessário usar a chave primária da tabela para carregar um item.

**nota**  
Para realizar essa operação em segundo plano, use o método `LoadAsync` em vez disso. Para ver um exemplo do uso do método `LoadAsync` para realizar operações CRUD de alto nível em uma tabela do DynamoDB, consulte o exemplo a seguir.

```
    /// <summary>
    /// Shows how to perform high-level CRUD operations on an Amazon DynamoDB
    /// table.
    /// </summary>
    public class HighLevelItemCrud
    {
        public static async Task Main()
        {
            var client = new AmazonDynamoDBClient();
            DynamoDBContext context = new DynamoDBContext(client);
            await PerformCRUDOperations(context);
        }

        public static async Task PerformCRUDOperations(IDynamoDBContext context)
        {
            int bookId = 1001; // Some unique value.
            Book myBook = new Book
            {
                Id = bookId,
                Title = "object persistence-AWS SDK for.NET SDK-Book 1001",
                Isbn = "111-1111111001",
                BookAuthors = new List<string> { "Author 1", "Author 2" },
            };

            // Save the book to the ProductCatalog table.
            await context.SaveAsync(myBook);

            // Retrieve the book from the ProductCatalog table.
            Book bookRetrieved = await context.LoadAsync<Book>(bookId);

            // Update some properties.
            bookRetrieved.Isbn = "222-2222221001";

            // Update existing authors list with the following values.
            bookRetrieved.BookAuthors = new List<string> { " Author 1", "Author x" };
            await context.SaveAsync(bookRetrieved);

            // Retrieve the updated book. This time, add the optional
            // ConsistentRead parameter using DynamoDBContextConfig object.
            await context.LoadAsync<Book>(bookId, new DynamoDBContextConfig
            {
                ConsistentRead = true,
            });

            // Delete the book.
            await context.DeleteAsync<Book>(bookId);

            // Try to retrieve deleted book. It should return null.
            Book deletedBook = await context.LoadAsync<Book>(bookId, new DynamoDBContextConfig
            {
                ConsistentRead = true,
            });

            if (deletedBook == null)
            {
                Console.WriteLine("Book is deleted");
            }
        }
    }
```

## Consulta
<a name="w2aac17b9c21c23c39c33"></a>

Consulta uma tabela com base em parâmetros de consulta que você fornece.

Você poderá consultar uma tabela somente se ela tiver uma chave primária composta (chave de partição e chave de classificação). Ao consultar, você deve especificar uma chave de partição e uma condição que se aplique à chave de classificação.

Suponha que você tenha uma classe `Reply` no lado do cliente mapeada na tabela `Reply` no DynamoDB. O exemplo de código C\$1 a seguir consulta a tabela `Reply` para encontrar respostas de tópicos de fórum postadas nos últimos 15 dias. A tabela `Reply` tem uma chave primária com a chave de partição `Id` e a chave de classificação `ReplyDateTime`.

**Example**  

```
DynamoDBContext context = new DynamoDBContext(client);

string replyId = "DynamoDB#DynamoDB Thread 1"; //Partition key
DateTime twoWeeksAgoDate = DateTime.UtcNow.Subtract(new TimeSpan(14, 0, 0, 0)); // Date to compare.
IEnumerable<Reply> latestReplies = context.Query<Reply>(replyId, QueryOperator.GreaterThan, twoWeeksAgoDate);
```

Isso retorna uma coleção de objetos `Reply`. 

Por padrão, o método `Query` retorna uma coleção `IEnumerable` de "carregamento preguiçoso". Ele inicialmente retorna apenas uma página de resultados e, em seguida, faz uma chamada de serviço para a próxima página, se necessário. Para obter todos os itens correspondentes, você só precisa fazer uma iteração na coleção `IEnumerable`.

Se a sua tabela tiver uma chave primária simples (chave de partição), você não poderá usar o método `Query`. Em vez disso, poderá usar o método `Load` e fornecer a chave de partição para recuperar o item.

**nota**  
Para realizar essa operação em segundo plano, use o método `QueryAsync` em vez disso.

## Save (Salvar)
<a name="w2aac17b9c21c23c39c35"></a>

Salva o objeto especificado na tabela. Se a chave primária especificada no objeto de entrada não existir na tabela, o método adicionará um novo item à tabela. Se a chave primária existir, o método atualizará o item existente.

Se você tiver o bloqueio otimista configurado, a atualização será bem-sucedida apenas se as versões do item no lado do cliente e no lado do servidor corresponderem. Para obter mais informações, consulte [Bloqueio positivo usando o DynamoDB e o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.VersionSupport.md).

**nota**  
Para realizar essa operação em segundo plano, use o método `SaveAsync` em vez disso.

## Verificar
<a name="w2aac17b9c21c23c39c37"></a>

Realiza uma verificação de tabela inteira. 

Você pode filtrar o resultado da verificação especificando uma condição de verificação. A condição pode ser avaliada em qualquer atributo da tabela. Suponha que você tenha uma classe `Book` no lado do cliente mapeada na tabela `ProductCatalog` no DynamoDB. O exemplo de código C\$1 a seguir verifica a tabela e retorna apenas os itens de livro com preços inferiores a 0.

**Example**  

```
IEnumerable<Book> itemsWithWrongPrice = context.Scan<Book>(
                    new ScanCondition("Price", ScanOperator.LessThan, price),
                    new ScanCondition("ProductCategory", ScanOperator.Equal, "Book")
      );
```

Por padrão, o método `Scan` retorna uma coleção `IEnumerable` de "carregamento preguiçoso". Ele inicialmente retorna apenas uma página de resultados e, em seguida, faz uma chamada de serviço para a próxima página, se necessário. Para obter todos os itens correspondentes, basta fazer uma iteração na coleção `IEnumerable`.

Por motivos de performance, você deve consultar suas tabelas e evitar uma verificação de tabela.

**nota**  
Para realizar essa operação em segundo plano, use o método `ScanAsync` em vez disso.

## ToDocument
<a name="w2aac17b9c21c23c39c39"></a>

Retorna uma instância da classe de modelo de documento `Document` da sua instância de classe. 

Isso será útil se você quiser usar as classes de modelo de documento junto com o modelo de persistência de objetos para realizar qualquer operação de dados. Para obter mais informações sobre as classes do modelo de documento fornecidas pelo AWS SDK para .NET, consulte [Trabalhar com o modelo de documento do .NET no DynamoDB](DotNetSDKMidLevel.md). 

Suponha que você tenha uma classe de cliente mapeada na tabela de exemplo `Forum`. É possível usar um `DynamoDBContext` para obter um item, como um objeto `Document` da tabela `Forum`, conforme mostrado no exemplo de código C\$1 a seguir.

**Example**  

```
DynamoDBContext context = new DynamoDBContext(client);

Forum forum101 = context.Load<Forum>(101); // Retrieve a forum by primary key.
Document doc = context.ToDocument<Forum>(forum101);
```

## Especificar parâmetros opcionais para DynamoDBContext
<a name="OptionalConfigParams"></a>

Ao usar o modelo de persistência de objeto, você pode especificar os seguintes parâmetros opcionais para `DynamoDBContext`.
+ **`ConsistentRead`**: ao recuperar dados usando as operações `Load`, `Query` ou `Scan`, você pode opcionalmente adicionar esse parâmetro para solicitar os valores mais recentes dos dados.
+ **`IgnoreNullValues`**: esse parâmetro instrui `DynamoDBContext` a ignorar valores nulos em atributos durante uma operação `Save`. Se esse parâmetro for false (ou se não estiver definido), um valor nulo será interpretado como uma diretiva para excluir o atributo específico. 
+ **`SkipVersionCheck`**: esse parâmetro instrui o `DynamoDBContext` a não comparar versões ao salvar ou excluir um item. Para obter mais informações sobre versionamento, consulte [Bloqueio positivo usando o DynamoDB e o modelo de persistência de objetos do AWS SDK para .NET](DynamoDBContext.VersionSupport.md).
+ **`TableNamePrefix`—** prefixa todos os nomes de tabelas com uma string específica. Se esse parâmetro for nulo (ou se não estiver definido), nenhum prefixo será usado.
+ `DynamoDBEntryConversion`: especifica o esquema de conversão usado pelo cliente. Você pode definir esse parâmetro para a versão V1 ou V2. A versão padrão é V1.

  O comportamento desse parâmetro pode mudar com base na versão definida. Por exemplo:
  + Na V1, o tipo de dados `bool` é convertido no tipo numérico `N`, em que 0 representa falso e 1 representa verdadeiro. Na V2, `bool` é convertido em `BOOL`.
  + Na V2, listas e matrizes não são agrupadas com HashSets. Listas e matrizes de números, tipos baseados em strings e tipos baseados em binários são convertidos no tipo `L` (Lista), que pode ser enviado vazio para atualizar uma lista. Isso é diferente da V1, em que uma lista vazia não é enviada pela rede.

    Na V1, os tipos de coleção, como lista, HashSet e matrizes, são tratados da mesma forma. Lista, HashSet e matriz de números são convertidos no tipo `NS` (conjunto de números). 

  O exemplo a seguir define a versão do esquema de conversão como V2, o que altera o comportamento de conversão entre os tipos .NET e os tipos de dados do DynamoDB.

  ```
  var config = new DynamoDBContextConfig
  {
      Conversion = DynamoDBEntryConversion.V2
  };
  var contextV2 = new DynamoDBContext(client, config);
  ```

O exemplo de código C\$1 a seguir cria um `DynamoDBContext` especificando dois dos parâmetros opcionais anteriores, `ConsistentRead` e `SkipVersionCheck`.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
...
DynamoDBContext context =
       new DynamoDBContext(client, new DynamoDBContextConfig { ConsistentRead = true, SkipVersionCheck = true});
```

`DynamoDBContext` inclui esses parâmetros opcionais com cada solicitação enviada usando esse contexto. 

Em vez de definir esses parâmetros no nível de `DynamoDBContext`, é possível especificá-los para operações individuais que você executa usando `DynamoDBContext`, conforme mostrado no exemplo de código C\$1 a seguir. O exemplo carrega um item de livro específico. O método `Load` de `DynamoDBContext` especifica os parâmetros `ConsistentRead` e `SkipVersionCheck` opcionais.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
...
DynamoDBContext context = new DynamoDBContext(client);
Book bookItem = context.Load<Book>(productId,new DynamoDBContextConfig{ ConsistentRead = true, SkipVersionCheck = true });
```

Nesse caso, `DynamoDBContext` inclui esses parâmetros somente ao enviar a solicitação `Get`.

# Bloqueio positivo usando o DynamoDB e o modelo de persistência de objetos do AWS SDK para .NET
<a name="DynamoDBContext.VersionSupport"></a>

O suporte para bloqueio otimista no modelo de persistência de objetos garante que a versão do item para a sua aplicação seja igual à versão do item no lado do servidor antes que esse item seja atualizado ou excluído. Suponha que você recupere um item para atualização. No entanto, antes de você retornar suas atualizações, outra aplicação atualiza o mesmo item. Agora, a aplicação tem uma cópia obsoleta do item. Sem o bloqueio otimista, qualquer atualização que você realizar substituirá a atualização feita pelo outro aplicativo. 

O recurso de bloqueio otimista do modelo de persistência de objetos fornece a tag `DynamoDBVersion` que você pode usar para habilitar o bloqueio otimista. Para usar esse recurso, adicione uma propriedade à sua classe para armazenar o número de versão. Você adiciona o atributo `DynamoDBVersion` à propriedade. Quando o objeto for salvo pela primeira vez, `DynamoDBContext` atribuirá um número de versão e incrementará esse valor cada vez que você atualizar o item. 

Sua solicitação de atualização ou exclusão só será bem-sucedida se a versão do objeto no lado do cliente corresponder ao número de versão correspondente do item no lado do servidor. Se a sua aplicação tiver uma cópia obsoleta, ela deverá obter a versão mais recente do servidor antes de poder atualizar ou excluir o item.

O exemplo de código C\$1 a seguir define uma classe `Book` com atributos de persistência de objetos mapeando-a na tabela `ProductCatalog`. A propriedade `VersionNumber` na classe decorada com o atributo `DynamoDBVersion` armazena o valor do número de versão.

**Example**  

```
[DynamoDBTable("ProductCatalog")]
  public class Book
  {
    [DynamoDBHashKey]   //Partition key
    public int Id { get; set; }
    [DynamoDBProperty]
    public string Title { get; set; }
    [DynamoDBProperty]
    public string ISBN { get; set; }
    [DynamoDBProperty("Authors")]
    public List<string> BookAuthors { get; set; }
    [DynamoDBVersion]
    public int? VersionNumber { get; set; }
  }
```

**nota**  
Você pode aplicar o atributo `DynamoDBVersion` apenas a um tipo primitivo numérico anulável (como `int?`). 

O bloqueio otimista tem o seguinte impacto sobre operações `DynamoDBContext`:
+ Para um novo item, `DynamoDBContext` atribui o número de versão inicial 0. Se você recuperar um item existente, atualizar uma ou mais das suas propriedades e tentar salvar as alterações, a operação de salvamento será bem-sucedida somente se o número de versão no lado do cliente e no lado do servidor corresponderem. `DynamoDBContext` incrementa o número de versão. Você não precisa definir o número de versão.
+ O método `Delete` fornece sobrecargas que podem usar um valor de chave primária ou um objeto como parâmetro, conforme mostrado no exemplo de código C\$1 a seguir.  
**Example**  

  ```
  DynamoDBContext context = new DynamoDBContext(client);
  ...
  // Load a book.
  Book book = context.Load<ProductCatalog>(111);
  // Do other operations.
  // Delete 1 - Pass in the book object.
  context.Delete<ProductCatalog>(book);
  
  // Delete 2 - Pass in the Id (primary key)
  context.Delete<ProductCatalog>(222);
  ```

  Se você fornecer um objeto como parâmetro, a exclusão apenas será bem-sucedida se a versão do objeto corresponder à versão de item no lado do servidor correspondente. No entanto, se você fornecer um valor de chave primária como parâmetro, `DynamoDBContext` desconhecerá qualquer número de versão e excluirá o item sem fazer a verificação de versão. 

  Observe que a implementação interna do bloqueio otimista no código do modelo de persistência de objetos usa as ações de API de atualização condicional e exclusão condicional no DynamoDB.

## Desabilitar o bloqueio positivo
<a name="DotNetDynamoDBContext.DisablingOptimisticLocking"></a>

Para desabilitar o bloqueio otimista, use a propriedade de configuração `SkipVersionCheck`. Você pode definir essa propriedade ao criar . `DynamoDBContext`. Nesse caso, o bloqueio otimista está desabilitado para solicitações feitas usando o contexto. Para obter mais informações, consulte [Especificar parâmetros opcionais para DynamoDBContext](DotNetDynamoDBContext.md#OptionalConfigParams). 

Em vez de definir a propriedade no nível do contexto, você pode desabilitar o bloqueio otimista para uma operação específica, conforme mostrado no exemplo de código C\$1 a seguir. O exemplo de código usa o contexto para excluir um item de livro. O método `Delete` define a propriedade `SkipVersionCheck` opcional como true, desabilitando a verificação de versão.

**Example**  

```
DynamoDBContext context = new DynamoDBContext(client);
// Load a book.
Book book = context.Load<ProductCatalog>(111);
...
// Delete the book.
context.Delete<Book>(book, new DynamoDBContextConfig { SkipVersionCheck = true });
```

# Mapear dados arbitrários com o DynamoDB usando o modelo de persistência de objetos do AWS SDK para .NET
<a name="DynamoDBContext.ArbitraryDataMapping"></a>

Além dos tipos de .NET compatíveis (consulte [Tipos de dados compatíveis](DotNetSDKHighLevel.md#DotNetDynamoDBContext.SupportedTypes)), é possível usar tipos em sua aplicação para os quais não há um mapeamento direto para os tipos do Amazon DynamoDB. O modelo de persistência de objetos oferece suporte ao armazenamento de dados de tipos arbitrários, desde que você forneça o conversor para converter dados do tipo arbitrário no tipo do DynamoDB e vice-versa. O código de conversor transforma os dados durante os processos de salvar e carregar os objetos.

É possível criar qualquer tipo no lado do cliente. No entanto, os dados armazenados nas tabelas são um dos tipos do DynamoDB e, durante a consulta e a verificação, qualquer comparação de dados feita baseia-se nos dados armazenados no DynamoDB.

O exemplo de código C\$1 a seguir define uma classe `Book` com as propriedades `Id`, `Title`, `ISBN` e `Dimension`. A propriedade `Dimension` é do `DimensionType`, que descreve as propriedades `Height`, `Width` e `Thickness`. O código de exemplo fornece os métodos de conversor `ToEntry` e `FromEntry` para converter dados entre o `DimensionType` e os tipos de string do DynamoDB. Por exemplo, ao salvar uma instância `Book`, o conversor cria uma string `Dimension` de livro como “8.5x11x.05". Quando você recupera um livro, ele converte a string em uma instância `DimensionType`.

O exemplo mapeia o tipo `Book` na tabela `ProductCatalog`. Ele salva uma instância `Book` de exemplo, recupera essa instância, atualiza suas dimensões e salva novamente o `Book` atualizado.



Para obter instruções passo a passo sobre como testar o exemplo a seguir, consulte [Exemplos de código .NET](CodeSamples.DotNet.md).

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class HighLevelMappingArbitraryData
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                DynamoDBContext context = new DynamoDBContext(client);

                // 1. Create a book.
                DimensionType myBookDimensions = new DimensionType()
                {
                    Length = 8M,
                    Height = 11M,
                    Thickness = 0.5M
                };

                Book myBook = new Book
                {
                    Id = 501,
                    Title = "AWS SDK for .NET Object Persistence Model Handling Arbitrary Data",
                    ISBN = "999-9999999999",
                    BookAuthors = new List<string> { "Author 1", "Author 2" },
                    Dimensions = myBookDimensions
                };

                context.Save(myBook);

                // 2. Retrieve the book.
                Book bookRetrieved = context.Load<Book>(501);

                // 3. Update property (book dimensions).
                bookRetrieved.Dimensions.Height += 1;
                bookRetrieved.Dimensions.Length += 1;
                bookRetrieved.Dimensions.Thickness += 0.2M;
                // Update the book.
                context.Save(bookRetrieved);

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }
    }
    [DynamoDBTable("ProductCatalog")]
    public class Book
    {
        [DynamoDBHashKey] //Partition key
        public int Id
        {
            get; set;
        }
        [DynamoDBProperty]
        public string Title
        {
            get; set;
        }
        [DynamoDBProperty]
        public string ISBN
        {
            get; set;
        }
        // Multi-valued (set type) attribute.
        [DynamoDBProperty("Authors")]
        public List<string> BookAuthors
        {
            get; set;
        }
        // Arbitrary type, with a converter to map it to DynamoDB type.
        [DynamoDBProperty(typeof(DimensionTypeConverter))]
        public DimensionType Dimensions
        {
            get; set;
        }
    }

    public class DimensionType
    {
        public decimal Length
        {
            get; set;
        }
        public decimal Height
        {
            get; set;
        }
        public decimal Thickness
        {
            get; set;
        }
    }

    // Converts the complex type DimensionType to string and vice-versa.
    public class DimensionTypeConverter : IPropertyConverter
    {
        public DynamoDBEntry ToEntry(object value)
        {
            DimensionType bookDimensions = value as DimensionType;
            if (bookDimensions == null) throw new ArgumentOutOfRangeException();

            string data = string.Format("{1}{0}{2}{0}{3}", " x ",
                            bookDimensions.Length, bookDimensions.Height, bookDimensions.Thickness);

            DynamoDBEntry entry = new Primitive
            {
                Value = data
            };
            return entry;
        }

        public object FromEntry(DynamoDBEntry entry)
        {
            Primitive primitive = entry as Primitive;
            if (primitive == null || !(primitive.Value is String) || string.IsNullOrEmpty((string)primitive.Value))
                throw new ArgumentOutOfRangeException();

            string[] data = ((string)(primitive.Value)).Split(new string[] { " x " }, StringSplitOptions.None);
            if (data.Length != 3) throw new ArgumentOutOfRangeException();

            DimensionType complexData = new DimensionType
            {
                Length = Convert.ToDecimal(data[0]),
                Height = Convert.ToDecimal(data[1]),
                Thickness = Convert.ToDecimal(data[2])
            };
            return complexData;
        }
    }
}
```

# Executar os exemplos de código neste Guia do desenvolvedor
<a name="CodeSamples"></a>

Os AWS SDKs fornecem um amplo suporte ao Amazon DynamoDB nas seguintes linguagens:
+ [ Java](https://aws.amazon.com/sdk-for-java)
+ [JavaScript no navegador](https://aws.amazon.com/sdk-for-browser)
+ [.NET](https://aws.amazon.com/sdk-for-net)
+ [Node.js](https://aws.amazon.com/sdk-for-node-js)
+ [PHP](https://aws.amazon.com/sdk-for-php)
+ [Python](https://aws.amazon.com/sdk-for-python)
+ [Ruby](https://aws.amazon.com/sdk-for-ruby)
+ [C\$1\$1](https://aws.amazon.com/sdk-for-cpp)
+ [Go](https://aws.amazon.com/sdk-for-go)
+ [Android](https://aws.amazon.com/mobile/sdk/)
+ [iOS](https://aws.amazon.com/mobile/sdk/)

Os exemplos de código neste guia do desenvolvedor fornecem uma cobertura mais detalhada das operações do DynamoDB usando as seguintes linguagens de programação:
+ [Exemplos de código Java](CodeSamples.Java.md)
+ [Exemplos de código .NET](CodeSamples.DotNet.md)

Antes de iniciar este exercício, será necessário criar uma conta da AWS, obter a chave de acesso e a chave secreta e configurar a AWS Command Line Interface (AWS CLI) no seu computador. Para obter mais informações, consulte [Configurar o DynamoDB (serviço da Web)](SettingUp.DynamoWebService.md).

**nota**  
Se estiver usando a versão para download do DynamoDB, você precisará usar a AWS CLI para criar as tabelas e os dados de exemplo. Também precisará especificar o parâmetro `--endpoint-url` com cada comando da AWS CLI. Para obter mais informações, consulte [Definir o endpoint local](DynamoDBLocal.UsageNotes.md#DynamoDBLocal.Endpoint).

# Criar tabelas e carregar dados para exemplos de código no DynamoDB
<a name="SampleData"></a>

Veja abaixo as noções básicas sobre como criar tabelas no DynamoDB, carregar um conjunto de dados de exemplo, consultar os dados e atualizá-los.
+ [Etapa 1: crie uma tabela no DynamoDB](getting-started-step-1.md)
+ [Etapa 2: grave dados em uma tabela do DynamoDB](getting-started-step-2.md)
+ [Etapa 3: leia os dados de uma tabela do DynamoDB](getting-started-step-3.md)
+ [Etapa 4: atualize os dados em uma tabela do DynamoDB](getting-started-step-4.md)

# Exemplos de código Java
<a name="CodeSamples.Java"></a>

**Topics**
+ [Java: configurar suas credenciais da AWS](#CodeSamples.Java.Credentials)
+ [Java: configurar a região e o endpoint da AWS](#CodeSamples.Java.RegionAndEndpoint)

Este Guia do Desenvolvedor contém trechos de código Java e programas prontos para serem executados. Você encontrará esses exemplos de código nas seguintes seções:
+ [Trabalhar com itens e atributos no DynamoDB](WorkingWithItems.md)
+ [Trabalhar com tabelas e dados no DynamoDB](WorkingWithTables.md)
+ [Consultar tabelas no DynamoDB](Query.md)
+ [Verificar tabelas no DynamoDB](Scan.md)
+ [Melhorar o acesso aos dados com índices secundários no DynamoDB](SecondaryIndexes.md)
+ [Java 1.x: DynamoDBMapper](DynamoDBMapper.md)
+ [Capturar dados de alterações para o DynamoDB Streams](Streams.md)

É possível começar rapidamente usando o Eclipse com o [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/). Além de um IDE completo, você também terá o AWS SDK para Java com atualizações automáticas e modelos pré-configurados para a compilação de aplicações da AWS.

**Como executar os exemplos de código Java (usando o Eclipse)**

1. Baixe e instale o IDE do [Eclipse](http://www.eclipse.org).

1. Baixe e instale a [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/).

1. Inicie o Eclipse e, no menu **Eclipse**, escolha **File (Arquivo)**, **New (Novo)** e **Other (Outro)**.

1. Em **Selecionar um assistente**, escolha **AWS**, **Projeto AWS Java** e **Próximo**.

1. Em **Criar um AWS Java**, faça o seguinte:

   1. Em **Nome do projeto**, digite um nome para o seu projeto.

   1. Em **Selecionar conta (Selecionar conta)**, escolha o perfil de suas credenciais na lista.

      Se essa for a primeira vez que você usa o [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/), escolha **Configurar contas da AWS** para configurar suas credenciais da AWS.

1. Escolha **Finish (Concluir)** para criar o projeto.

1. No menu do **Eclipse**, escolha **File (Arquivo)**, **New (Novo)** e, em seguida, **Class (Classe)**.

1. Em **Java Class (Classe Java)**, digite um nome para a sua classe em **Name (Nome)** (use o mesmo nome que o exemplo de código que você deseja executar) e escolha **Finish (Concluir)** para criar a classe.

1. Copie o exemplo de código da página de documentação no editor do Eclipse.

1. Para executar o código, escolha **Run (Executar)** no menu do Eclipse.

O SDK for Java fornece clientes thread-safe para trabalhar com o DynamoDB. De acordo com as melhores práticas, seus aplicativos devem criar um único cliente e reutilizá-lo entre os threads.

Para obter mais informações, consulte a [AWS SDK para Java](https://aws.amazon.com/sdk-for-java).

**nota**  
Os exemplos de código neste guia são destinados para uso com a versão mais recente do AWS SDK para Java.  
Se estiver usando o AWS Toolkit for Eclipse, você poderá configurar atualizações automáticas para o SDK for Java. Para fazer isso no Eclipse, vá para **Preferences** (Preferências) e escolha **AWS Toolkit**, **AWS SDK para Java** e **Download new SDKs automatically** (Fazer download automático de novos SDKs).

## Java: configurar suas credenciais da AWS
<a name="CodeSamples.Java.Credentials"></a>

O SDK for Java exige que você forneça credenciais da AWS para a sua aplicação em tempo de execução. Os exemplos de código neste guia pressupõem que você esteja usando um arquivo de credenciais da AWS, conforme descrito em [Configurar suas credenciais da AWS](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/set-up-creds.html) no *Guia do desenvolvedor da AWS SDK para Java*.

Veja a seguir um exemplo de um arquivo de credenciais da AWS chamado `~/.aws/credentials` em que o caractere de til (`~`) representa seu diretório inicial.

```
[default]
aws_access_key_id = AWS access key ID goes here
aws_secret_access_key = Secret key goes here
```

## Java: configurar a região e o endpoint da AWS
<a name="CodeSamples.Java.RegionAndEndpoint"></a>

Por padrão, os exemplos de código acessam o DynamoDB na região Oeste dos EUA (Oregon). É possível alterar a região ao modificar as propriedades `AmazonDynamoDB`.

O exemplo de código a seguir instancia uma nova `AmazonDynamoDB`.

```
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import com.amazonaws.regions.Regions;
...
// This client will default to US West (Oregon)
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
.withRegion(Regions.US_WEST_2)
.build();
```

É possível usar o método `withRegion` para executar seu código no DynamoDB em qualquer região em que ele está disponível. Para obter uma lista completa, consulte [Regiões e endpoints da AWS](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region), na *Referência geral da Amazon Web Services*.

Se desejar executar os exemplos de código usando o DynamoDB localmente no seu computador, defina o endpoint conforme descrito a seguir.

### AWS SDK V1
<a name="CodeSamples.Java.RegionAndEndpoint.V1"></a>

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "us-west-2"))
.build();
```

### AWS SDK V2
<a name="CodeSamples.Java.RegionAndEndpoint.V2"></a>

```
DynamoDbClient client = DynamoDbClient.builder()
    .endpointOverride(URI.create("http://localhost:8000"))
    // The region is meaningless for local DynamoDb but required for client builder validation
    .region(Region.US_EAST_1)
    .credentialsProvider(StaticCredentialsProvider.create(
    AwsBasicCredentials.create("dummy-key", "dummy-secret")))
    .build();
```

# Exemplos de código .NET
<a name="CodeSamples.DotNet"></a>

**Topics**
+ [.NET: configurar as suas credenciais da AWS](#CodeSamples.DotNet.Credentials)
+ [.NET: configurar a região e o endpoint da AWS](#CodeSamples.DotNet.RegionAndEndpoint)

Este guia contém trechos de código .NET e programas prontos para serem executados. Você encontrará esses exemplos de código nas seguintes seções:
+ [Trabalhar com itens e atributos no DynamoDB](WorkingWithItems.md)
+ [Trabalhar com tabelas e dados no DynamoDB](WorkingWithTables.md)
+ [Consultar tabelas no DynamoDB](Query.md)
+ [Verificar tabelas no DynamoDB](Scan.md)
+ [Melhorar o acesso aos dados com índices secundários no DynamoDB](SecondaryIndexes.md)
+ [Trabalhar com o modelo de documento do .NET no DynamoDB](DotNetSDKMidLevel.md)
+ [Trabalhar com o modelo de persistência de objetos do .NET e o DynamoDB](DotNetSDKHighLevel.md)
+ [Capturar dados de alterações para o DynamoDB Streams](Streams.md)

Você pode começar rapidamente usando o AWS SDK para .NET com o Toolkit for Visual Studio.

**Como executar os exemplos de código .NET (usando o Visual Studio)**

1. Baixe e instale o [Microsoft Visual Studio](https://www.visualstudio.com).

1. (Opcional) Baixe e instale o [Toolkit for Visual Studio](https://aws.amazon.com/visualstudio/).

1. Configure suas credenciais AWS. Configure um perfil de credenciais em seu arquivo de credenciais compartilhadas da AWS (`~/.aws/credentials`). Para obter mais informações, consulte [Configurar credenciais da AWS](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html) no *Guia do desenvolvedor do AWS SDK para .NET*.

1. Inicie o Visual Studio. Escolha **File (Arquivo)**, **New (Novo)**, **Project (Projeto)**.

1. Busque por **Console App**, selecione o modelo C\$1 que tem como alvo o.NET e escolha **Avançar**. Configure o nome e a localização do projeto e, em seguida, escolha **Criar**.

1. Adicione o pacote do NuGet para o AWS SDK para DynamoDB ao projeto:

   1. No Solution Explorer, abra o menu de contexto (clique com o botão direito do mouse) do seu projeto e escolha **Manage NuGet Packages (Gerenciar pacotes do NuGet)**.

   1. No Gerenciador de pacotes NuGet, escolha **Browse (Procurar)**.

   1. Na caixa de pesquisa, digite **AWSSDK.DynamoDBv2** e aguarde a conclusão da pesquisa.

   1. Escolha **AWSSDK.DynamoDBv2** e **Install (Instalar)**.

1. Em seu projeto do Visual Studio, abra `Program.cs`. Substitua o conteúdo pelo exemplo de código da página de documentação que você deseja executar.

1. Para executar o código, escolha **Start (Iniciar)** na barra de ferramentas do Visual Studio.

O SDK para .NET fornece clientes thread-safe para trabalhar com o DynamoDB. De acordo com as melhores práticas, seus aplicativos devem criar um único cliente e reutilizá-lo entre os threads.

Para obter mais informações, consulte [AWS SDK for .NET](https://aws.amazon.com/sdk-for-net).

**nota**  
Os exemplos de código neste guia são destinados para uso com a versão mais recente do AWS SDK para .NET.

## .NET: configurar as suas credenciais da AWS
<a name="CodeSamples.DotNet.Credentials"></a>

O SDK para .NET exige que você forneça credenciais da AWS para a sua aplicação em tempo de execução. Os exemplos de código neste guia pressupõem que você esteja usando o SDK Store para gerenciar seu arquivo de credenciais da AWS, conforme descrito em [Usar o SDK Store](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#sdk-store) no *Guia do desenvolvedor do AWS SDK para .NET*.

O Toolkit for Visual Studio oferece suporte a vários conjuntos de credenciais de qualquer número de contas. Cada conjunto é chamado de *perfil*. O Visual Studio adiciona entradas ao arquivo `App.config` do projeto para que a sua aplicação possa encontrar as credenciais da AWS em tempo de execução.

O exemplo a seguir mostra o arquivo `App.config` padrão que é gerado ao criar um novo projeto usando o Toolkit for Visual Studio.

```
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
    <add key="AWSProfileName" value="default"/>
    <add key="AWSRegion" value="us-west-2" />
 </appSettings>
</configuration>
```

Em tempo de execução, o programa usa o conjunto `default` de credenciais da AWS, conforme especificado pela entrada `AWSProfileName`. As credenciais da AWS são mantidas no SDK Store em formato criptografado. O Toolkit for Visual Studio fornece uma interface gráfica do usuário para gerenciar suas credenciais no Visual Studio. Para obter mais informações, consulte [Specifying credentials](https://docs.aws.amazon.com/AWSToolkitVS/latest/UserGuide/tkv_setup.html#creds) (Especificar credenciais) no *AWS Toolkit for Visual Studio User Guide* (Guia do usuário do ).

**nota**  
Por padrão, os exemplos de código acessam o DynamoDB na região Oeste dos EUA (Oregon). É possível alterar a região ao modificar a entrada `AWSRegion` no arquivo App.config. É possível definir `AWSRegion` como qualquer região em que o DynamoDB está disponível. Para obter uma lista completa, consulte [Regiões e endpoints da AWS](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region), na *Referência geral da Amazon Web Services*.

## .NET: configurar a região e o endpoint da AWS
<a name="CodeSamples.DotNet.RegionAndEndpoint"></a>

Por padrão, os exemplos de código acessam o DynamoDB na região Oeste dos EUA (Oregon). É possível alterar a região ao modificar a entrada `AWSRegion` no arquivo `App.config`. É possível alterar a região ao modificar as propriedades `AmazonDynamoDBClient`.

O exemplo de código a seguir instancia uma nova `AmazonDynamoDBClient`. O cliente é modificado de forma que o código seja executado no DynamoDB em uma região diferente.

```
AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig();
// This client will access the US East 1 region.
clientConfig.RegionEndpoint = RegionEndpoint.USEast1;
AmazonDynamoDBClient client = new AmazonDynamoDBClient(clientConfig);
```

Para obter uma lista completa de regiões, consulte [Regiões e endpoints da AWS](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region) na *Referência geral da Amazon Web Services*.

Se desejar executar os exemplos de código usando o DynamoDB localmente no seu computador, defina o endpoint conforme descrito a seguir.

```
AmazonDynamoDBConfig clientConfig = new AmazonDynamoDBConfig();
// Set the endpoint URL
clientConfig.ServiceURL = "http://localhost:8000";
AmazonDynamoDBClient client = new AmazonDynamoDBClient(clientConfig);
```

# API de baixo nível do DynamoDB
<a name="Programming.LowLevelAPI"></a>

A *API de baixo nível* do Amazon DynamoDB é a interface de nível de protocolo para DynamoDB. Nesse nível, cada solicitação de HTTP(S) deve ser corretamente formatada e ter uma assinatura digital válida.

Os AWS SDKs criam solicitações da API do DynamoDB de baixo nível em seu nome e processam as respostas no DynamoDB. Isso permite que você se concentre na lógica do seu aplicativo, em vez de detalhes de baixo nível. No entanto, você ainda pode se beneficiar de um conhecimento básico de como a API de baixo nível do DynamoDB funciona.

Para obter mais informações sobre a API de baixo nível do DynamoDB, consulte a [Referência da API do Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/).

**nota**  
O DynamoDB Streams tem sua própria API de baixo nível, que é separada do DynamoDB e tem suporte total dos AWS SDKs.  
Para obter mais informações, consulte [Capturar dados de alterações para o DynamoDB Streams](Streams.md). Para obter a API de baixo nível do DynamoDB Streams, consulte a [Referência da API do Amazon DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Operations_Amazon_DynamoDB_Streams.html).

A API de baixo nível do DynamoDB usa a JavaScript Object Notation (JSON) como um formato de protocolo de conexão. O JSON apresenta dados em uma hierarquia de forma que os valores e a estrutura dos dados sejam transmitidos simultaneamente. O pares de nome-valor são definidos no formato `name:value`. A hierarquia de dados é definida por colchetes aninhados de pares de nome-valor.

O DynamoDB usa JSON somente como um protocolo de transporte, não como um formato de armazenamento. Os AWS SDKs usam JSON para enviar dados ao DynamoDB, e o DynamoDB responde com JSON. O DynamoDB não armazena dados persistentemente no formato JSON.

**nota**  
Para obter mais informações sobre JSON [Introdução ao JSON](http://json.org) site `JSON.org`.

**Topics**
+ [Formato de solicitação](#Programming.LowLevelAPI.RequestFormat)
+ [Formato de resposta](#Programming.LowLevelAPI.ResponseFormat)
+ [Descritores de tipo de dados](#Programming.LowLevelAPI.DataTypeDescriptors)
+ [Dados numéricos](#Programming.LowLevelAPI.Numbers)
+ [Dados binários](#Programming.LowLevelAPI.Binary)

![\[API de baixo nível do DynamoDB e como os SDKs da AWS lidam com as solicitações e respostas em nível de protocolo.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/SDKSupport.DDBLowLevelAPI.png)


## Formato de solicitação
<a name="Programming.LowLevelAPI.RequestFormat"></a>

A API de baixo nível do DynamoDB aceita solicitações `POST` HTTP(S) como entrada. Os AWS SDKs criam essas solicitações para você.

Vamos supor que você tenha uma tabela chamada `Pets`, com um esquema de chaves que consiste em `AnimalType` (chave de partição) e `Name` (chave de classificação). Ambos os atributos são do tipo `string`. Para recuperar um item de `Pets`, o AWS SDK cria a solicitação a seguir.

```
POST / HTTP/1.1
Host: dynamodb.<region>.<domain>;
Accept-Encoding: identity
Content-Length: <PayloadSizeBytes>
User-Agent: <UserAgentString>
Content-Type: application/x-amz-json-1.0
Authorization: AWS4-HMAC-SHA256 Credential=<Credential>, SignedHeaders=<Headers>, Signature=<Signature>
X-Amz-Date: <Date> 
X-Amz-Target: DynamoDB_20120810.GetItem

{
    "TableName": "Pets",
    "Key": {
        "AnimalType": {"S": "Dog"},
        "Name": {"S": "Fido"}
    }
}
```

Observe o seguinte sobre essa solicitação:
+ O cabeçalho `Authorization` contém as informações necessárias para o DynamoDB autenticar a solicitação. Para obter mais informações, consulte [Assinar solicitações de API da AWS](https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html) e [Processo de assinatura do Signature versão 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) na *Referência geral da Amazon Web Services*.
+ O cabeçalho `X-Amz-Target` contém o nome de uma operação do DynamoDB: `GetItem`. (Isso também é acompanhado pela versão da API de baixo nível, neste caso `20120810`.)
+ A carga útil (corpo) da solicitação contém os parâmetros da operação, no formato JSON. Para a operação `GetItem`, os parâmetros são `TableName` e `Key`.

## Formato de resposta
<a name="Programming.LowLevelAPI.ResponseFormat"></a>

Após o recebimento da solicitação, o DynamoDB a processa e retorna uma resposta. Para a solicitação mostrada anteriormente, a carga de resposta HTTP(S) contém os resultados da operação, conforme mostrado no exemplo a seguir.

```
HTTP/1.1 200 OK
x-amzn-RequestId: <RequestId>
x-amz-crc32: <Checksum>
Content-Type: application/x-amz-json-1.0
Content-Length: <PayloadSizeBytes>
Date: <Date>
{
    "Item": {
        "Age": {"N": "8"},
        "Colors": {
            "L": [
                {"S": "White"},
                {"S": "Brown"},
                {"S": "Black"}
            ]
        },
        "Name": {"S": "Fido"},
        "Vaccinations": {
            "M": {
                "Rabies": {
                    "L": [
                        {"S": "2009-03-17"},
                        {"S": "2011-09-21"},
                        {"S": "2014-07-08"}
                    ]
                },
                "Distemper": {"S": "2015-10-13"}
            }
        },
        "Breed": {"S": "Beagle"},
        "AnimalType": {"S": "Dog"}
    }
}
```

Neste momento, o AWS SDK retorna os dados da resposta para sua aplicação para processamento adicional.

**nota**  
Se o DynamoDB não puder processar uma solicitação, ele retornará uma mensagem e um código de erro HTTP. O AWS SDK propaga esses elementos em sua aplicação na forma de exceções. Para obter mais informações, consulte [Tratamento de erros com o DynamoDB](Programming.Errors.md).

## Descritores de tipo de dados
<a name="Programming.LowLevelAPI.DataTypeDescriptors"></a>

O protocolo da API de baixo nível do DynamoDB exige que cada atributo seja acompanhado por um descritor de tipo de dados. *Descritores de tipos de dados* são tokens que informam ao DynamoDB como interpretar cada atributo.

Os exemplos em [Formato de solicitação](#Programming.LowLevelAPI.RequestFormat) e [Formato de resposta](#Programming.LowLevelAPI.ResponseFormat) mostram exemplos de como os descritores de tipo de dados são usados. A solicitação `GetItem` especifica `S` para os atributos de esquema de chaves de `Pets` (`AnimalType` e `Name`), que são do tipo `string`. A resposta `GetItem` contém o item *Pets* com atributos do tipo `string` (`S`), `number` (`N`), `map` (`M`) e `list` (`L`).

Veja a seguir uma lista completa dos descritores de tipos de dados do DynamoDB:
+ **`S`** – string
+ **`N`** – número
+ **`B`** – binário
+ **`BOOL`** – booliano
+ **`NULL`** – nulo
+ **`M`** – mapa
+ **`L`** – lista
+ **`SS`** – conjunto de strings
+ **`NS`** – conjunto de números
+ **`BS`** – conjunto binário

A tabela a seguir mostra o formato de JSON correto para cada descritor de tipo de dados. Observe que os números são representados como strings para preservar a precisão, enquanto os boolianos e nulos usam os respectivos tipos JSON nativos.


| Descritor | Formato JSON | Observações | 
| --- | --- | --- | 
| S | \$1"S": "Hello"\$1 | O valor é uma string JSON. | 
| N | \$1"N": "123.45"\$1 | O valor é uma string, não um número JSON. Isso preserva a precisão em todos as linguagens. | 
| B | \$1"B": "dGhpcyBpcyBhIHRlc3Q="\$1 | O valor é uma string codificada em base64. | 
| BOOL | \$1"BOOL": true\$1 | O valor é um booliano JSON (true ou false), não uma string. | 
| NULL | \$1"NULL": true\$1 | O valor é o booliano JSON true para indicar nulo. | 
| M | \$1"M": \$1"Name": \$1"S": "Joe"\$1\$1\$1 | O valor é um objeto JSON de pares de nome-valor do atributo. | 
| L | \$1"L": [\$1"S": "Red"\$1, \$1"N": "5"\$1]\$1 | O valor é uma matriz de valores de atributo JSON. | 
| SS | \$1"SS": ["Red", "Blue"]\$1 | O valor é uma matriz de strings JSON. | 
| NS | \$1"NS": ["1", "2.5"]\$1 | O valor é uma matriz de strings JSON de números. | 
| BS | \$1"BS": ["U3Vubnk=", "UmFpbnk="]\$1 | O valor é uma matriz de strings JSON codificadas em base64. | 

**nota**  
 Para obter descrições detalhadas dos tipos de dados do DynamoDB, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

## Dados numéricos
<a name="Programming.LowLevelAPI.Numbers"></a>

As diferentes linguagens de programação oferecem diferentes níveis de suporte para JSON. Em alguns casos, é possível decidir usar uma biblioteca de terceiros para validar e analisar documentos JSON.

Algumas bibliotecas de terceiros se desenvolvem com base no tipo número do JSON, fornecendo seus próprios tipos, como `int`, `long` ou `double`. No entanto, o tipo de dados de número nativo no DynamoDB não é mapeado exatamente nesses outros tipos de dados, portanto, essas distinções de tipo podem causar conflitos. Além disso, muitas bibliotecas do JSON não manipulam valores numéricos de precisão fixa, e elas inferem automaticamente um tipo de dados duplo para sequências de dígitos que contêm um separador decimal.

Para solucionar esses problemas, o DynamoDB fornece um único tipo numérico sem perda de dados. Para evitar conversões implícitas indesejadas para um valor duplo, o DynamoDB usa strings para a transferência de dados de valores numéricos. Essa abordagem fornece flexibilidade para atualizar valores de atributo, sem deixar de manter a semântica de classificação adequada, como colocar os valores "01", "2" e "03" na sequência apropriada.

Se a precisão numérica for importante para sua aplicação, você deverá converter valores numéricos em strings antes de passá-los para o DynamoDB.

## Dados binários
<a name="Programming.LowLevelAPI.Binary"></a>

O DynamoDB oferece suporte a atributos binários. No entanto, o JSON não é originalmente compatível com a codificação de dados binários. Para enviar dados binários em uma solicitação, será necessário codificá-los em formato base64. Ao receber a solicitação, o DynamoDB decodifica os dados em base64 de volta para binário. 

O esquema de codificação base64 usado pelo DynamoDB é descrito na [RFC 4648](http://tools.ietf.org/html/rfc4648) no site da Internet Engineering Task Force (IETF).

# Programar o Amazon DynamoDB com Python e Boto3
<a name="programming-with-python"></a>

Este guia fornece uma orientação para programadores que desejam usar o Amazon DynamoDB com Python. Saiba mais sobre as diferentes camadas de abstração, gerenciamento de configuração, tratamento de erros, controle de políticas de novas tentativas, gerenciamento de keep-alive e muito mais.

**Topics**
+ [Sobre o Boto](#programming-with-python-about)
+ [Usar a documentação do Boto](#programming-with-python-documentation)
+ [Noções básicas sobre as camadas de abstração do cliente e de recursos](#programming-with-python-client-resource)
+ [Usar o recurso de tabela batch\$1writer](#programming-with-python-batch-writer)
+ [Exemplos de código adicionais que exploram as camadas do cliente e de recursos](#programming-with-python-additional-code)
+ [Noções básicas sobre como os objetos Client e Resource interagem com sessões e threads](#programming-with-python-sessions-thread-safety)
+ [Personalizar o objeto Config](#programming-with-python-config)
+ [Tratamento de erros](#programming-with-python-error-handling)
+ [Registro em log](#programming-with-python-logging)
+ [Hooks de eventos](#programming-with-python-event-hooks)
+ [Paginação e o paginador](#programming-with-python-pagination)
+ [Waiters](#programming-with-python-waiters)

## Sobre o Boto
<a name="programming-with-python-about"></a>

É possível acessar o DynamoDB por meio do Python usando o SDK da AWS oficial para Python, geralmente chamado de **Boto3**. O nome Boto se origina de um golfinho de água doce nativo do Rio Amazonas. A biblioteca Boto3 é a terceira versão principal da biblioteca, lançada pela primeira vez em 2015. A biblioteca Boto3 é bem grande, pois comporta todos os serviços da AWS, não apenas o DynamoDB. Essa orientação visa somente às partes do Boto3 relevantes para o DynamoDB.

O Boto é mantido pela AWS como um projeto de código aberto hospedado no GitHub. Ele é dividido em dois pacotes: [Botocore](https://github.com/boto/botocore) e [Boto3](https://github.com/boto/boto3).
+ O **Botocore** oferece a funcionalidade de nível inferior. No Botocore, você encontrará o cliente, a sessão, as credenciais, a configuração e as classes de exceção. 
+ O **Boto3** se baseia no Botocore. Ele oferece uma interface de nível superior, mais relacionada ao Python. Especificamente, ele expõe uma tabela do DynamoDB como um recurso e oferece uma interface mais simples e elegante em comparação à interface de cliente orientada a serviços, de nível inferior.

Como esses projetos estão hospedados no GitHub, é possível visualizar o código-fonte, rastrear problemas abertos ou enviar seus próprios problemas.

## Usar a documentação do Boto
<a name="programming-with-python-documentation"></a>

Comece a usar a documentação do Boto com os seguintes recursos:
+ Comece com a [seção Início rápido](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html), que fornece um ponto de partida sólido para a instalação do pacote. Acesse-a para receber instruções sobre como instalar o Boto3, caso ele ainda não esteja instalado (em geral, o Boto3 é disponibilizado automaticamente nos serviços da AWS, como o AWS Lambda.
+ Depois disso, concentre-se no [guia do DynamoDB](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/dynamodb.html) da documentação. Ele mostra como realizar as atividades básicas do DynamoDB: criar e excluir tabelas, manipular itens, além de realizar operações em lote, consultas e verificações. Seus exemplos usam a interface de **recursos**. A exibição de `boto3.resource('dynamodb')` indica que você está usando a interface de **recursos** de nível superior.
+ Depois do guia, você pode analisar a [referência do DynamoDB](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html). Essa página de pouso fornece uma lista completa das classes e dos métodos disponíveis. Na parte superior, será exibida a classe `DynamoDB.Client`. Ela concede acesso de nível inferior a todas as operações do ambiente de gerenciamento e do plano de dados. Na parte inferior, é exibida a classe `DynamoDB.ServiceResource`. Trata-se da interface relacionada ao Python de nível superior. Com ela, é possível criar tabelas, realizar operações em lote entre tabelas ou ter acesso a uma instância `DynamoDB.ServiceResource.Table` para ações específicas de tabelas.

## Noções básicas sobre as camadas de abstração do cliente e de recursos
<a name="programming-with-python-client-resource"></a>

As duas interfaces com as quais você trabalhará são a interface do **cliente** e a interface de **recursos**. 
+ A interface do **cliente** de nível inferior oferece um mapeamento de um para um para a API de serviço subjacente. Todas as APIs oferecidas pelo DynamoDB estão disponíveis por meio do cliente. Isso significa que a interface do cliente pode fornecer funcionalidade completa, mas geralmente é mais detalhada e complexa de usar.
+ A interface de **recursos** de nível superior não fornece um mapeamento de um para um da API de serviço subjacente. No entanto, ela oferece métodos que tornam mais conveniente o acesso ao serviço, como `batch_writer`.

Veja a seguir um exemplo de inserção de um item usando a interface do cliente. Observe como todos os valores são transmitidos como um mapa com a chave indicando o tipo (“S” para string, “N” para número) e o valor como string. Isso é conhecido como formato JSON do DynamoDB.

```
import boto3

dynamodb = boto3.client('dynamodb')

dynamodb.put_item(
    TableName='YourTableName',
    Item={
        'pk': {'S': 'id#1'},
        'sk': {'S': 'cart#123'},
        'name': {'S': 'SomeName'},
        'inventory': {'N': '500'},
        # ... more attributes ...
    }
)
```

Aqui está a mesma operação `PutItem` usando a interface de recursos. A digitação dos dados está implícita:

```
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('YourTableName')

table.put_item(
    Item={
        'pk': 'id#1',
        'sk': 'cart#123',
        'name': 'SomeName',
        'inventory': 500,
        # ... more attributes ...
    }
)
```

Se necessário, será possível converter entre JSON normal e JSON do DynamoDB usando as classes `TypeSerializer` e `TypeDeserializer` fornecidas com o boto3:

```
def dynamo_to_python(dynamo_object: dict) -> dict:
    deserializer = TypeDeserializer()
    return {
        k: deserializer.deserialize(v) 
        for k, v in dynamo_object.items()
    }  
  
def python_to_dynamo(python_object: dict) -> dict:
    serializer = TypeSerializer()
    return {
        k: serializer.serialize(v)
        for k, v in python_object.items()
    }
```

Veja como realizar uma consulta usando a interface do cliente. Ela expressa a consulta como uma estrutura JSON. Ela usa uma string `KeyConditionExpression` que exige a substituição de variáveis para lidar com possíveis conflitos de palavras-chave:

```
import boto3

client = boto3.client('dynamodb')

# Construct the query
response = client.query(
    TableName='YourTableName',
    KeyConditionExpression='pk = :pk_val AND begins_with(sk, :sk_val)',
    FilterExpression='#name = :name_val',
    ExpressionAttributeValues={
        ':pk_val': {'S': 'id#1'},
        ':sk_val': {'S': 'cart#'},
        ':name_val': {'S': 'SomeName'},
    },
    ExpressionAttributeNames={
        '#name': 'name',
    }
)
```

A mesma operação de consulta usando a interface de recursos pode ser reduzida e simplificada:

```
import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('YourTableName')

response = table.query(
    KeyConditionExpression=Key('pk').eq('id#1') & Key('sk').begins_with('cart#'),
    FilterExpression=Attr('name').eq('SomeName')
)
```

Como exemplo final, imagine que você queira ter o tamanho aproximado de uma tabela (que são metadados mantidos na tabela que são atualizados a cada seis horas). Com a interface do cliente, você precisa realizar uma operação `describe_table()` e extrair a resposta da estrutura JSON exibida:

```
import boto3

dynamodb = boto3.client('dynamodb')

response = dynamodb.describe_table(TableName='YourTableName')
size = response['Table']['TableSizeBytes']
```

Com a interface de recursos, a tabela realiza a operação describe implicitamente e apresenta os dados diretamente como um atributo:

```
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('YourTableName')
size = table.table_size_bytes
```

**nota**  
Ao pensar na possibilidade de desenvolver usando a interface do cliente ou de recursos, esteja ciente de que novos recursos não serão adicionados à interface de recursos de acordo com a [documentação de recursos](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html): “A equipe do AWS SDK para Python não pretende adicionar novos recursos à interface de recursos no boto3. As interfaces existentes continuarão funcionando durante o ciclo de vida do boto3. Os clientes podem encontrar acesso a novos recursos de serviço por meio da interface do cliente”.

## Usar o recurso de tabela batch\$1writer
<a name="programming-with-python-batch-writer"></a>

Uma praticidade disponível somente com o recurso de tabela de nível superior é o `batch_writer`. O DynamoDB comporta operações de gravação em lote, permitindo até 25 operações put ou delete em uma solicitação de rede. O agrupamento em lotes como esse melhora a eficiência ao minimizar as viagens de ida e volta da rede.

Com a biblioteca de cliente de nível inferior, você deve usar a operação `client.batch_write_item()` para executar lotes. É necessário dividir manualmente o trabalho em lotes de 25. Depois de cada operação, você também precisa solicitar o recebimento de uma lista de itens não processados (algumas das operações de gravação podem ser bem-sucedidas, enquanto outras podem falhar). Depois, é necessário transmitir esses itens não processados novamente para uma operação `batch_write_item()` posterior. Há uma quantidade significativa de código clichê.

O método [Table.batch\$1writer](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/batch_writer.html) cria um gerenciador de contexto para gravar objetos em um lote. Ele apresenta uma interface em que parece que você está escrevendo itens um de cada vez, mas internamente está armazenando em buffer e enviando os itens em lotes. Ele também lida com novas tentativas de itens não processados implicitamente.

```
dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('YourTableName')

movies = # long list of movies in {'pk': 'val', 'sk': 'val', etc} format
with table.batch_writer() as writer:
    for movie in movies:
        writer.put_item(Item=movie)
```

## Exemplos de código adicionais que exploram as camadas do cliente e de recursos
<a name="programming-with-python-additional-code"></a>

Também é possível consultar os seguintes repositórios de exemplos de código que exploram o uso das várias funções, usando o cliente e o recurso:
+ [Exemplos oficiais de código de ação única da AWS.](https://docs.aws.amazon.com/code-library/latest/ug/python_3_dynamodb_code_examples.html) 
+ [Exemplos oficiais de código orientado por cenários da AWS.](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python)
+ [Exemplos de códigos de ação única mantidos pela comunidade.](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/python)

## Noções básicas sobre como os objetos Client e Resource interagem com sessões e threads
<a name="programming-with-python-sessions-thread-safety"></a>

O objeto Resource não é seguro para threads e não deve ser compartilhado entre threads ou processos. Consulte o [guia sobre recursos](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html#multithreading-or-multiprocessing-with-resources) para ter mais detalhes.

O objeto Client, por outro lado, geralmente é seguro para threads, exceto para recursos avançados específicos. Consulte o [guia sobre clientes](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html#multithreading-or-multiprocessing-with-clients) para ter mais detalhes. 

O objeto Session não é seguro para threads. Portanto, toda vez que você criar um cliente ou um recurso em um ambiente de vários threads, primeiro será necessário criar uma sessão e, depois, o cliente ou o recurso por meio da sessão. Consulte o [guia sobre sessões](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html#multithreading-or-multiprocessing-with-sessions) para ter mais detalhes. 

Ao chamar o `boto3.resource()`, você está usando implicitamente a sessão padrão. Isso é conveniente para escrever código de thread único. Ao escrever código de vários threads, primeiro é necessário criar uma sessão para cada thread e, depois, recuperar o recurso dessa sessão:

```
# Explicitly create a new Session for this thread 
session = boto3.Session()
dynamodb = session.resource('dynamodb')
```

## Personalizar o objeto Config
<a name="programming-with-python-config"></a>

Ao criar um objeto Client ou Resource, é possível transmitir parâmetros nomeados opcionais para personalizar o comportamento. O parâmetro chamado `config` disponibiliza uma série de funcionalidades. É uma instância de `botocore.client.Config` e a [documentação de referência do Config](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) mostra todos os itens expostos a serem controlados. O [guia de configuração](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html) fornece uma visão geral útil.

**nota**  
É possível modificar muitas dessas configurações comportamentais em nível de sessão, no arquivo de configuração AWS ou como variáveis de ambiente.

**Configuração de tempos limite**

Um dos usos de uma configuração personalizada é ajustar os comportamentos de rede:
+ **connect\$1timeout (float ou int)**: o tempo em segundos até que uma exceção de tempo limite seja lançada ao tentar fazer uma conexão. O padrão é 60 segundos.
+ **connect\$1timeout (float ou int)**: o tempo em segundos até que uma exceção de tempo limite seja lançada ao tentar estabelecer uma conexão. O padrão é 60 segundos.

Tempos limite de sessenta segundos são excessivos para o DynamoDB. Isso significa que uma falha transitória na rede causará um minuto de atraso para o cliente antes que ele possa tentar novamente. O código a seguir reduz os tempos limite para um segundo:

```
import boto3
from botocore.config import Config

my_config = Config(
   connect_timeout = 1.0,
   read_timeout = 1.0
)
dynamodb = boto3.resource('dynamodb', config=my_config)
```

Para ler mais discussões sobre tempos limite, consulte [Tuning AWS Java SDK HTTP request settings for latency-aware DynamoDB applications](https://aws.amazon.com/blogs/database/tuning-aws-java-sdk-http-request-settings-for-latency-aware-amazon-dynamodb-applications/). Observe que o SDK do Java tem mais configurações de tempo limite do que o Python.

**Configuração de keep-alive**

Se estiver usando o botocore 1.27.84 ou posterior, você também poderá controlar o **TCP Keep-Alive**:
+ **tcp\$1keepalive** (bool): habilita a opção de soquete TCP Keep-Alive usada ao criar conexões, se definida como `True` (o padrão é `False`). O recurso está disponível apenas a partir do botocore 1.27.84.

Configurar o TCP Keep-Alive como `True` pode reduzir as latências médias. Veja um exemplo de código que define condicionalmente o TCP Keep-Alive como verdadeiro quando você tem a versão correta do botocore:

```
import botocore
import boto3
from botocore.config import Config
from distutils.version import LooseVersion

required_version = "1.27.84"
current_version = botocore.__version__

my_config = Config(
   connect_timeout = 0.5,
   read_timeout = 0.5
)
if LooseVersion(current_version) > LooseVersion(required_version):
    my_config = my_config.merge(Config(tcp_keepalive = True))

dynamodb = boto3.resource('dynamodb', config=my_config)
```

**nota**  
O TCP Keep-Alive é diferente do HTTP Keep-Alive. Com o TCP Keep-Alive, pacotes pequenos são enviados pelo sistema operacional subjacente pela conexão do soquete para manter a conexão ativa e detectar imediatamente qualquer queda. Com o HTTP Keep-Alive, a conexão da web baseada no soquete subjacente é reutilizada. O HTTP Keep-Alive está sempre habilitado com o boto3.

Há um limite de quanto tempo uma conexão inativa pode ser mantida ativa. Pense em enviar solicitações periódicas (digamos a cada minuto) se tiver uma conexão inativa, mas quiser que a próxima solicitação use uma conexão já estabelecida.

**Configuração de novas tentativas**

A configuração também aceita um dicionário chamado **novas tentativas**, no qual é possível especificar o comportamento de novas tentativas desejado. As novas tentativas acontecem no SDK quando o SDK recebe um erro e o erro é de um tipo transitório. Se um erro for repetido internamente (e uma nova tentativa, por fim, produzir uma resposta bem-sucedida), do ponto de vista do código de chamada, não haverá erro, apenas uma latência ligeiramente elevada. Veja os valores que você pode especificar:
+ **max\$1attempts**: um número inteiro que representa o número máximo de novas tentativas que serão feitas em uma única solicitação. Por exemplo, definir esse valor como dois fará com que a solicitação seja repetida no máximo duas vezes após a solicitação inicial. Definir esse valor como zero não vai ocasionar nenhuma nova tentativa após a solicitação inicial. 
+ **total\$1max\$1attempts**: um número inteiro que representa o número máximo total de tentativas que serão feitas em uma única solicitação. Isso inclui a solicitação inicial, portanto, um valor de um indica que nenhuma solicitação será repetida. Se `total_max_attempts` e `max_attempts` forem fornecidos, `total_max_attempts` terá precedência. `total_max_attempts` é preferível a `max_attempts` porque é associado à variável de ambiente `AWS_MAX_ATTEMPTS` e ao valor do arquivo de configuração `max_attempts`.
+ **mode**: uma string que representa o tipo de modo de nova tentativa que o botocore deve usar. Os valores válidos são:
  + **legacy**: o modo padrão. Espera 50 ms na primeira tentativa e, depois, usa recuo exponencial com um fator de base dois. Em relação ao DynamoDB, ele executa até dez tentativas no total, (a menos que seja substituído pelo valor acima).
**nota**  
Com um recuo exponencial, a última tentativa aguardará quase 13 segundos.
  + **standard**: padrão nomeado porque é mais consistente com outros SDKs da AWS. Espera por um período aleatório que varia de 0 ms a 1.000 ms pela primeira nova tentativa. Se outra nova tentativa for necessária, ele escolherá outro período aleatório de 0 ms a 1.000 ms e o multiplicará por 2. Se for necessária uma nova tentativa, ele fará a mesma escolha aleatória multiplicada por quatro e assim por diante. Cada espera é limitada a 20 segundos. Esse modo executará novas tentativas em mais condições de falha detectadas do que o modo `legacy`. Em relação ao DynamoDB, ele executa até três tentativas no total, (a menos que seja substituído pelo valor acima). 
  + **adaptável**: modo de novas tentativas experimental que inclui toda a funcionalidade do modo padrão, mas inclui controle de utilização automática do lado do cliente. Com a limitação de taxa adaptável, os SDKs podem diminuir a taxa na qual as solicitações são enviadas para acomodar melhor a capacidade dos serviços da AWS. Esse é um modo provisório cujo comportamento pode mudar. 

Uma definição expandida desses modos de novas tentativas pode ser encontrada no [guia de novas tentativas](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html), bem como no [tópico Retry behavior na referência do SDK](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html).

Veja um exemplo que usa explicitamente a política de novas tentativas `legacy` com, no máximo, três 3 solicitações no total (duas novas tentativas):

```
import boto3
from botocore.config import Config

my_config = Config(
   connect_timeout = 1.0,
   read_timeout = 1.0,
   retries = {
     'mode': 'legacy',
     'total_max_attempts': 3
   }
)
dynamodb = boto3.resource('dynamodb', config=my_config)
```

Como o DynamoDB é um sistema de alta disponibilidade e baixa latência, convém adotar uma postura mais incisiva em relação à velocidade das novas tentativas do que as respectivas políticas permitem. É possível implementar sua própria política de novas tentativas definindo o máximo de tentativas como zero, detectando por conta própria as exceções e tentando novamente, conforme apropriado, com o próprio código, em vez de recorrer ao boto3 para fazer novas tentativas implícitas.

Se você gerencia sua própria política de novas tentativas, convém diferenciar entre controles de utilização e erros:
+ Um **controle de utilização** (designado por um `ProvisionedThroughputExceededException` ou `ThrottlingException`) indica um serviço íntegro que está informando que você excedeu sua capacidade de leitura ou gravação em uma tabela ou partição do DynamoDB. A cada milissegundo que se passa, um pouco mais de capacidade de leitura ou gravação é disponibilizada e, portanto, é possível realizar novas tentativas com rapidez (por exemplo, a cada 50 ms) para tentar acessar essa capacidade recém-liberada. Com os controles de utilização, não é especialmente necessário um recuo exponencial porque os controles de utilização são leves para o DynamoDB exibir e não cobram por solicitação. O recuo exponencial atribui atrasos maiores aos threads do cliente que já esperaram por mais tempo, o que estende estatisticamente o p50 e o p99.
+ Um **erro** (designado por um `InternalServerError` ou um `ServiceUnavailable`, entre outros) indica um problema transitório com o serviço. Isso pode se relacionar à toda a tabela ou possivelmente apenas à partição na qual você está lendo ou gravando. Com erros, é possível pausar por mais tempo antes de novas tentativas, (como 250 ms ou 500 ms), e usar a instabilidade para escalonar as novas tentativas.

**Configuração de conexões máximas de grupo**

Por fim, a configuração permite controlar o tamanho do grupo de conexões:
+ **max\$1pool\$1connections (int)**: o número máximo de conexões a serem mantidas em um grupo de conexões. Se esse valor não for definido, será usado o valor padrão dez.

Essa opção controla o número máximo de conexões HTTP a serem mantidas agrupadas para reutilização. Um grupo diferente é mantido por sessão. Ao prever que mais de dez threads serão direcionados para clientes ou recursos criados na mesma sessão, pense em aumentar isso, para que os threads não precisem esperar por outros threads usando uma conexão em grupo.

```
import boto3
from botocore.config import Config

my_config = Config(
   max_pool_connections = 20
)

# Setup a single session holding up to 20 pooled connections
session = boto3.Session(my_config)

# Create up to 20 resources against that session for handing to threads
# Notice the single-threaded access to the Session and each Resource
resource1 = session.resource('dynamodb')
resource2 = session.resource('dynamodb')
# etc
```

## Tratamento de erros
<a name="programming-with-python-error-handling"></a>

Nem todas as exceções de serviço da AWS são definidas estaticamente no Boto3. Isso ocorre porque os erros e as exceções dos serviços da AWS variam muito e estão sujeitos a alterações. O Boto3 agrupa todas as exceções de serviço como um `ClientError` e expõe os detalhes como JSON estruturado. Por exemplo, uma resposta de erro pode ser estruturada assim:

```
{
    'Error': {
        'Code': 'SomeServiceException',
        'Message': 'Details/context around the exception or error'
    },
    'ResponseMetadata': {
        'RequestId': '1234567890ABCDEF',
        'HostId': 'host ID data will appear here as a hash',
        'HTTPStatusCode': 400,
        'HTTPHeaders': {'header metadata key/values will appear here'},
        'RetryAttempts': 0
    }
}
```

O código a seguir captura todas as exceções `ClientError` e examina o valor da string do `Code` no `Error` para determinar qual ação realizar:

```
import botocore
import boto3

dynamodb = boto3.client('dynamodb')

try:
    response = dynamodb.put_item(...)

except botocore.exceptions.ClientError as err:
    print('Error Code: {}'.format(err.response['Error']['Code']))
    print('Error Message: {}'.format(err.response['Error']['Message']))
    print('Http Code: {}'.format(err.response['ResponseMetadata']['HTTPStatusCode']))
    print('Request ID: {}'.format(err.response['ResponseMetadata']['RequestId']))

    if err.response['Error']['Code'] in ('ProvisionedThroughputExceededException', 'ThrottlingException'):
        print("Received a throttle")
    elif err.response['Error']['Code'] == 'InternalServerError':
        print("Received a server error")
    else:
        raise err
```

Alguns códigos de exceção (mas não todos) foram materializados como classes de nível superior. É possível optar por lidar com eles diretamente. Ao usar a interface do cliente, essas exceções são preenchidas dinamicamente no cliente e você captura essas exceções usando sua instância cliente, da seguinte maneira:

```
except ddb_client.exceptions.ProvisionedThroughputExceededException:
```

Ao usar a interface de recursos, é necessário usar `.meta.client` para fazer o percurso entre o recurso e o cliente subjacente a fim de acessar as exceções, da seguinte maneira:

```
except ddb_resource.meta.client.exceptions.ProvisionedThroughputExceededException:
```

Para analisar a lista de tipos de exceções materializadas, é possível gerar a lista dinamicamente:

```
ddb = boto3.client("dynamodb")
print([e for e in dir(ddb.exceptions) if e.endswith('Exception') or e.endswith('Error')])
```

Ao realizar uma operação de gravação com uma expressão condicional, é possível solicitar que, se a expressão falhar, o valor do item seja exibido na resposta de erro.

```
try:
    response = table.put_item(
        Item=item,
        ConditionExpression='attribute_not_exists(pk)',
        ReturnValuesOnConditionCheckFailure='ALL_OLD'
    )
except table.meta.client.exceptions.ConditionalCheckFailedException as e:
    print('Item already exists:', e.response['Item'])
```

Para ler mais sobre tratamento de erros e exceções:
+ O [guia do boto3 sobre tratamento de erros](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/error-handling.html) tem mais informações sobre técnicas de tratamento de erros. 
+ A [seção do Guia do desenvolvedor do DynamoDB sobre erros de programação](Programming.Errors.md) lista os erros que você pode encontrar. 
+ A [seção Common Errors na referência da API](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/CommonErrors.html).
+ A documentação sobre cada operação de API lista quais erros essa chamada pode gerar (por exemplo, [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html)).

## Registro em log
<a name="programming-with-python-logging"></a>

A biblioteca do boto3 se integra ao módulo de registro em log integrado do Python para monitorar o que acontece durante uma sessão. Para controlar os níveis de registro em log, é possível configurar o módulo de registro em log:

```
import logging

logging.basicConfig(level=logging.INFO)
```

Isso configura o logger raiz para registrar em log `INFO` e mensagens de nível superior. Mensagens de registro em log que forem menos rígidas do que o nível serão ignoradas. Os níveis de registro em log incluem `DEBUG`, `INFO`, `WARNING`, `ERROR` e `CRITICAL`. O padrão é `WARNING`.

Os loggers no boto3 são hierárquicos. A biblioteca usa alguns loggers diferentes, cada um correspondendo a diferentes partes da biblioteca. É possível controlar separadamente o comportamento de cada um:
+ **boto3**: o logger principal do módulo boto3.
+ **botocore**: o logger principal do pacote do botocore.
+ **botocore.auth**: usado para registrar em log a criação de assinaturas da AWS para solicitações.
+ **botocore.credentials**: usado para registrar em log o processo de busca e atualização de credenciais.
+ **botocore.endpoint**: usado para registrar em log a criação da solicitação antes de ser enviada pela rede.
+ **botocore.hooks**: usado para registrar em log eventos acionados na biblioteca.
+ **botocore.loaders**: usado para registrar em log quando partes dos modelos de serviço da AWS são carregadas.
+ **botocore.parsers**: usado para registrar em log as respostas do serviço da AWS antes de serem analisadas.
+ **botocore.retryhandler**: usado para registrar em log o processamento de novas tentativas de solicitação do serviço da AWS (modo herdado).
+ **botocore.retries.standard**: usado para registrar em log o processamento de novas tentativas de solicitação do serviço da AWS (modo padrão ou adaptável).
+ **botocore.utils**: usado para registrar em log atividades diversas na biblioteca.
+ **botocore.waiter**: usado para registrar em log a funcionalidade dos waiters, que pesquisam um serviço da AWS até que determinado estado seja atingido. 

Outras bibliotecas também realizam o registro em log. Internamente, o boto3 usa o urllib3 de terceiros para lidar com a conexão HTTP. Quando a latência é importante, é possível observar os logs para garantir que o grupo esteja sendo bem utilizado, vendo quando o urllib3 estabelece uma nova conexão ou fecha uma ociosa.
+ **urllib3.connectionpool:** use para registrar em log eventos de tratamento de eventos do grupo de conexões.

O trecho de código a seguir define a maioria dos registros em log como `INFO` com o registro em log de `DEBUG` da atividade do endpoint e do grupo de conexões:

```
import logging

logging.getLogger('boto3').setLevel(logging.INFO)
logging.getLogger('botocore').setLevel(logging.INFO)
logging.getLogger('botocore.endpoint').setLevel(logging.DEBUG)
logging.getLogger('urllib3.connectionpool').setLevel(logging.DEBUG)
```

## Hooks de eventos
<a name="programming-with-python-event-hooks"></a>

O Botocore emite eventos durante várias partes de sua execução. É possível registrar manipuladores para esses eventos para que, sempre que um evento for emitido, seu manipulador seja chamado. Isso permite que você estenda o comportamento do botocore sem precisar modificar os componentes internos.

Por exemplo, digamos que você queira acompanhar cada vez que uma operação `PutItem` for chamada em qualquer tabela do DynamoDB na aplicação. É possível se inscrever no evento `'provide-client-params.dynamodb.PutItem'` para capturar e registrar toda vez que uma operação `PutItem` for invocada na sessão associada. Veja um exemplo abaixo:

```
import boto3
import botocore
import logging

def log_put_params(params, **kwargs):
    if 'TableName' in params and 'Item' in params:
        logging.info(f"PutItem on table {params['TableName']}: {params['Item']}")

logging.basicConfig(level=logging.INFO)

session = boto3.Session()
event_system = session.events

# Register our interest in hooking in when the parameters are provided to PutItem
event_system.register('provide-client-params.dynamodb.PutItem', log_put_params)

# Now, every time you use this session to put an item in DynamoDB,
# it will log the table name and item data.
dynamodb = session.resource('dynamodb')
table = dynamodb.Table('YourTableName')
table.put_item(
    Item={
        'pk': '123',
        'sk': 'cart#123',
        'item_data': 'YourItemData',
        # ... more attributes ...
    }
)
```

No manipulador, é possível até mesmo manipular os parâmetros programaticamente para alterar o comportamento:

```
params['TableName'] = "NewTableName"
```

Para ter mais informações sobre eventos, consulte a [documentação do botocore sobre eventos](https://botocore.amazonaws.com/v1/documentation/api/latest/topics/events.html) e a [documentação do boto3 sobre eventos](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/events.html).

## Paginação e o paginador
<a name="programming-with-python-pagination"></a>

Algumas solicitações, como Query e Scan, limitam o tamanho dos dados exibidos em uma única solicitação e exigem que você faça solicitações repetidas para extrair as páginas subsequentes.

É possível controlar o número máximo de itens a serem lidos em cada página com o parâmetro `limit`. Por exemplo, se você quiser os dez últimos itens, poderá usar `limit` para recuperar somente os últimos dez itens. Observe que esse limite é quantos itens devem ser lidos da tabela antes que qualquer filtragem seja aplicada. Não há como especificar que você deseja exatamente dez após a filtragem; só é possível controlar a contagem pré-filtrada e conferir o lado do cliente quando realmente tiver recuperado dez itens. Independentemente do limite, cada resposta sempre tem um tamanho máximo de 1 MB.

Se a resposta incluir uma `LastEvaluatedKey`, isso indica que a resposta foi encerrada porque atingiu um limite de contagem ou tamanho. A chave é a última avaliada para a resposta. É possível recuperar essa `LastEvaluatedKey` e transmiti-la para uma chamada de acompanhamento como `ExclusiveStartKey` para ler a próxima parte desse ponto de partida. Quando não há `LastEvaluatedKey` exibida, isso significa que não há mais itens que correspondam a Query ou Scan.

Veja um exemplo simples (usando a interface de recursos, mas a interface do cliente tem o mesmo padrão) que lê no máximo cem itens por página e se repete até que todos os itens tenham sido lidos.

```
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('YourTableName')

query_params = {
    'KeyConditionExpression': Key('pk').eq('123') & Key('sk').gt(1000),
    'Limit': 100
}

while True:
    response = table.query(**query_params)

    # Process the items however you like
    for item in response['Items']:
        print(item)

    # No LastEvaluatedKey means no more items to retrieve
    if 'LastEvaluatedKey' not in response:
        break

    # If there are possibly more items, update the start key for the next page
    query_params['ExclusiveStartKey'] = response['LastEvaluatedKey']
```

Por conveniência, o boto3 pode fazer isso por você com paginadores. No entanto, ele só funciona com a interface do cliente. Veja o código reformulado para usar paginadores:

```
import boto3

dynamodb = boto3.client('dynamodb')

paginator = dynamodb.get_paginator('query')

query_params = {
    'TableName': 'YourTableName',
    'KeyConditionExpression': 'pk = :pk_val AND sk > :sk_val',
    'ExpressionAttributeValues': {
        ':pk_val': {'S': '123'},
        ':sk_val': {'N': '1000'},
    },
    'Limit': 100
}

page_iterator = paginator.paginate(**query_params)

for page in page_iterator:
    # Process the items however you like
    for item in page['Items']:
        print(item)
```

Para ter mais informações, consulte o [Guia sobre paginadores](https://botocore.amazonaws.com/v1/documentation/api/latest/topics/events.html) e a [Referência da API para DynamoDB.Paginator.Query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/paginator/Query.html).

**nota**  
Os paginadores também têm suas próprias configurações chamadas `MaxItems`, `StartingToken` e `PageSize`. Para paginar com o DynamoDB, você deve ignorar essas configurações.

## Waiters
<a name="programming-with-python-waiters"></a>

Os waiters oferecem a capacidade de esperar que algo seja concluído antes de continuar. No momento, eles comportam apenas a espera pela criação ou a exclusão de uma tabela. Em segundo plano, a operação waiter faz uma verificação para você a cada 20 segundos até 25 vezes. É possível fazer isso por conta própria, mas o uso de um waiter é uma solução mais sofisticada ao elaborar automações.

Esse código mostra como esperar que uma tabela específica seja criada:

```
# Create a table, wait until it exists, and print its ARN
response = client.create_table(...)
waiter = client.get_waiter('table_exists')
waiter.wait(TableName='YourTableName')
print('Table created:', response['TableDescription']['TableArn']
```

Para ter mais informações, consulte o [Guia de waiters](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html#waiters) e a [Referência sobre waiters](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#waiters).

# Programar o Amazon DynamoDB com JavaScript
<a name="programming-with-javascript"></a>

Este guia fornece uma orientação para programadores que desejam usar o Amazon DynamoDB com JavaScript. Saiba mais sobre o AWS SDK para JavaScript, camadas de abstração disponíveis, configuração de conexões, tratamento de erros, definição de políticas de novas tentativas, gerenciamento de keep alive e muito mais.

**Topics**
+ [Sobre o AWS SDK para JavaScript](#programming-with-javascript-about)
+ [Usar o AWS SDK para JavaScript V3](#programming-with-javascript-using-the-sdk)
+ [Acessar a documentação do JavaScript](#programming-with-javascript-documentation)
+ [Camadas de abstração](#programming-with-javascript-abstraction-layers)
+ [Usar a função de utilitário de ordenação](#programming-with-javascript-using-marshall-utility)
+ [Ler itens](#programming-with-javascript-reading-items)
+ [Gravações condicionais](#programming-with-javascript-conditional-writes)
+ [Paginação](#programming-with-javascript-pagination)
+ [Especificar a configuração](#programming-with-javascript-config)
+ [Waiters](#programming-with-javascript-waiters)
+ [Tratamento de erros](#programming-with-javascript-error-handling)
+ [Registro em log](#programming-with-javascript-logging)
+ [Considerações](#programming-with-javascript-considerations)

## Sobre o AWS SDK para JavaScript
<a name="programming-with-javascript-about"></a>

O AWS SDK para JavaScript concede acesso a Serviços da AWS usando scripts do navegador ou Node.js. Esta documentação concentra-se na versão mais recente do SDK (V3). O AWS SDK para JavaScript V3 é mantido pela AWS como um [projeto de código aberto hospedado no GitHub](https://github.com/aws/aws-sdk-js-v3). Os problemas e as solicitações de recursos são públicos e você pode acessá-los na página de problemas do repositório do GitHub.

O JavaScript V2 é semelhante ao V3, mas contém diferenças de sintaxe. A V3 é mais modular, facilitando o envio de dependências menores e tem suporte de primeira classe para TypeScript. Recomendamos o uso da versão mais recente do SDK.

## Usar o AWS SDK para JavaScript V3
<a name="programming-with-javascript-using-the-sdk"></a>

É possível adicionar o SDK ao à aplicação Node.js usando o Node Package Manager. Os exemplos abaixo mostram como adicionar os pacotes de SDK mais comuns para trabalhar com o DynamoDB.
+ `npm install @aws-sdk/client-dynamodb`
+ `npm install @aws-sdk/lib-dynamodb`
+ `npm install @aws-sdk/util-dynamodb`

A instalação de pacotes adiciona referências à seção de dependências do arquivo de projeto package.json. Você tem a opção de usar a sintaxe mais recente do módulo ECMAScript. Para ter mais detalhes sobre essas duas abordagens, consulte a seção Considerações.

## Acessar a documentação do JavaScript
<a name="programming-with-javascript-documentation"></a>

Comece a usar a documentação do JavaScript com os seguintes recursos:
+ Acesse o [Guia do desenvolvedor](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html) para ver a documentação básica do JavaScript. As instruções de instalação estão localizadas na seção **Configuração**.
+ Acesse a documentação de [referência da API](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/introduction/) para examinar todas as classes e os métodos disponíveis.
+ O SDK para JavaScript é compatível com muitos outros Serviços da AWS além do DynamoDB. Use o seguinte procedimento para localizar uma cobertura de API específica para o DynamoDB:

  1. Em **Serviços**, selecione **DynamoDB e bibliotecas**. Isso documenta o cliente de nível baixo.

  1. Selecione **lib-dynamodb**. Isso documenta o cliente de alto nível. Os dois clientes representam duas camadas de abstração diferentes que você tem a opção de usar. Consulte a seção a seguir para ter mais informações sobre camadas de abstração.

## Camadas de abstração
<a name="programming-with-javascript-abstraction-layers"></a>

O SDK para JavaScript V3 tem um cliente de nível inferior (`DynamoDBClient`) e um cliente de alto nível (`DynamoDBDocumentClient`).

**Topics**
+ [Cliente de nível inferior (`DynamoDBClient`)](#programming-with-javascript-low-level-client)
+ [Cliente de alto nível (`DynamoDBDocumentClient`)](#programming-with-javascript-high-level-client)

### Cliente de nível inferior (`DynamoDBClient`)
<a name="programming-with-javascript-low-level-client"></a>

O cliente de nível inferior não fornece abstrações extras sobre o protocolo de conexão subjacente. Ele oferece controle total sobre todos os aspectos da comunicação, mas como não há abstrações, é necessário realizar tarefas, como fornecer definições de itens usando o formato JSON do DynamoDB. 

Como mostra o exemplo abaixo, com esse formato, os tipos de dados devem ser declarados explicitamente. Um *S* indica um valor de string e um *N* indica um valor numérico. Os números na rede são sempre enviados como strings marcadas como tipos de números para garantir que não haja perda de precisão. As chamadas de API de nível inferior têm um padrão de nomenclatura, como `PutItemCommand` e `GetItemCommand`.

O exemplo a seguir está usando um cliente de nível inferior com um `Item` definido usando JSON do DynamoDB:

```
const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

async function addProduct() {
  const params = {
    TableName: "products",
    Item: {
      "id": { S: "Product01" },
      "description": { S: "Hiking Boots" },
      "category": { S: "footwear" },
      "sku": { S: "hiking-sku-01" },
      "size": { N: "9" }
    }
  };

  try {
    const data = await client.send(new PutItemCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}
addProduct();
```

### Cliente de alto nível (`DynamoDBDocumentClient`)
<a name="programming-with-javascript-high-level-client"></a>

O cliente de documentos de alto nível do DynamoDB oferece recursos de conveniência integrados, como eliminar a necessidade de organizar dados manualmente e permitir leituras e gravações diretas usando objetos JavaScript padrão. A [documentação do `lib-dynamodb`](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-lib-dynamodb/) fornece a lista de vantagens.

Para instanciar o `DynamoDBDocumentClient`, crie um `DynamoDBClient` de nível inferior e, depois, envolva-o com um `DynamoDBDocumentClient`. A convenção de nomenclatura da função difere um pouco entre os dois pacotes. Por exemplo, o nível inferior usa `PutItemCommand` enquanto o alto nível usa `PutCommand`. Os nomes distintos permitem que os dois conjuntos de funções coexistam no mesmo contexto, permitindo que você misture os dois no mesmo script.

```
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});

const docClient = DynamoDBDocumentClient.from(client);

async function addProduct() {
  const params = {
    TableName: "products",
    Item: {
      id: "Product01",
      description: "Hiking Boots",
      category: "footwear",
      sku: "hiking-sku-01",
      size: 9,
    },
  };

  try {
    const data = await docClient.send(new PutCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}

addProduct();
```

O padrão de uso é consistente ao ler itens usando operações de API, como `GetItem`, `Query` ou `Scan`.

## Usar a função de utilitário de ordenação
<a name="programming-with-javascript-using-marshall-utility"></a>

É possível usar o cliente de nível inferior e ordenar ou desordenar os tipos de dados por conta própria. O pacote de utilitários, [util-dynamodb](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-util-dynamodb/), tem uma função de utilitário `marshall()` que aceita JSON e produz JSON do DynamoDB, além de uma função `unmarshall()` que faz o contrário. O exemplo a seguir usa o cliente de nível inferior com a ordenação de dados gerenciada pela chamada `marshall()`.

```
const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");
const { marshall } = require("@aws-sdk/util-dynamodb");

const client = new DynamoDBClient({});

async function addProduct() {
  const params = {
    TableName: "products",
    Item: marshall({
      id: "Product01",
      description: "Hiking Boots",
      category: "footwear",
      sku: "hiking-sku-01",
      size: 9,
    }),
  };

  try {
    const data = await client.send(new PutItemCommand(params));
  } catch (error) {
    console.error("Error:", error);
  }
}
addProduct();
```

## Ler itens
<a name="programming-with-javascript-reading-items"></a>

Para ler um único item do DynamoDB use a operação de API `GetItem`. Semelhante ao comando `PutItem`, você tem a opção de usar o cliente de nível inferior ou o cliente Document de alto nível. O exemplo abaixo demonstra o uso do cliente Document de alto nível para recuperar um item.

```
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, GetCommand } = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});

const docClient = DynamoDBDocumentClient.from(client);

async function getProduct() {
  const params = {
    TableName: "products",
    Key: {
      id: "Product01",
    },
  };

  try {
    const data = await docClient.send(new GetCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}

getProduct();
```

Use a operação de API `Query` para ler vários itens. É possível usar o cliente de nível inferior ou o cliente Document. O exemplo abaixo usa o cliente Document de alto nível.

```
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const {
  DynamoDBDocumentClient,
  QueryCommand,
} = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});

const docClient = DynamoDBDocumentClient.from(client);

async function productSearch() {
  const params = {
    TableName: "products",
    IndexName: "GSI1",
    KeyConditionExpression: "#category = :category and begins_with(#sku, :sku)",
    ExpressionAttributeNames: {
      "#category": "category",
      "#sku": "sku",
    },
    ExpressionAttributeValues: {
      ":category": "footwear",
      ":sku": "hiking",
    },
  };

  try {
    const data = await docClient.send(new QueryCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}

productSearch();
```

## Gravações condicionais
<a name="programming-with-javascript-conditional-writes"></a>

As operações de gravação do DynamoDB podem especificar uma expressão de condição lógica que deve ser avaliada como verdadeira para que a gravação continue. Se a condição não for avaliada como verdadeira, a operação de gravação gerará uma exceção. A expressão da condição pode conferir se o item já existe ou se seus atributos correspondem a determinadas restrições.

`ConditionExpression = "version = :ver AND size(VideoClip) < :maxsize" `

Quando a expressão condicional falha, é possível usar `ReturnValuesOnConditionCheckFailure` para solicitar que a resposta de erro inclua o item que não atendeu às condições para deduzir qual era o problema. Para ter mais detalhes, consulte [Handle conditional write errors in high concurrency scenarios with Amazon DynamoDB](https://aws.amazon.com/blogs/database/handle-conditional-write-errors-in-high-concurrency-scenarios-with-amazon-dynamodb/).

```
try {
      const response = await client.send(new PutCommand({
          TableName: "YourTableName",
          Item: item,
          ConditionExpression: "attribute_not_exists(pk)",
          ReturnValuesOnConditionCheckFailure: "ALL_OLD"
      }));
  } catch (e) {
      if (e.name === 'ConditionalCheckFailedException') {
          console.log('Item already exists:', e.Item);
      } else {
          throw e;
      }
  }
```

Exemplos de código adicionais mostrando outros aspectos do uso do SDK V3 do JavaScript estão disponíveis na [documentação do SDK V3 do JavaScript](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_dynamodb_code_examples.html) e no [repositório DynamoDB-SDK-Examples do GitHub](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/node.js).

## Paginação
<a name="programming-with-javascript-pagination"></a>

**Topics**
+ [Usar o método de conveniência `paginateScan`](#using-the-paginatescan-convenience-method)

Solicitações de leitura, como `Scan` ou `Query`, provavelmente exibirão vários itens em um conjunto de dados. Se você executar `Scan` ou `Query` com um parâmetro `Limit`, depois que o sistema ler tantos itens, uma resposta parcial será enviada e você precisará paginar para recuperar itens adicionais.

O sistema só lerá no máximo 1 megabyte de dados por solicitação. Se você incluir uma expressão `Filter`, o sistema ainda lerá um megabyte, no máximo, de dados do disco, mas exibirá os itens desse megabyte que corresponderem ao filtro. A operação de filtro pode exibir 0 itens para uma página, mas ainda exigir mais paginação antes que a pesquisa seja concluída.

Você deve procurar `LastEvaluatedKey` na resposta e usá-la como o parâmetro `ExclusiveStartKey` em uma solicitação subsequente para continuar a recuperação de dados. Isso serve como um marcador, conforme observado no exemplo a seguir.

**nota**  
A amostra transmite um `lastEvaluatedKey` nulo como `ExclusiveStartKey` na primeira iteração e isso é permitido.

Exemplo: usando a `LastEvaluatedKey`:

```
const { DynamoDBClient, ScanCommand } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

async function paginatedScan() {
  let lastEvaluatedKey;
  let pageCount = 0;

  do {
    const params = {
      TableName: "products",
      ExclusiveStartKey: lastEvaluatedKey,
    };

    const response = await client.send(new ScanCommand(params));
    pageCount++;
    console.log(`Page ${pageCount}, Items:`, response.Items);
    lastEvaluatedKey = response.LastEvaluatedKey;
  } while (lastEvaluatedKey);
}

paginatedScan().catch((err) => {
  console.error(err);
});
```

### Usar o método de conveniência `paginateScan`
<a name="using-the-paginatescan-convenience-method"></a>



O SDK fornece métodos de conveniência chamados `paginateScan` e `paginateQuery` que fazem esse trabalho para você e faz as solicitações repetidas nos bastidores. Especifique o número máximo de itens a serem lidos por solicitação usando o parâmetro `Limit` padrão.

```
const { DynamoDBClient, paginateScan } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

async function paginatedScanUsingPaginator() {
  const params = {
    TableName: "products",
    Limit: 100
  };

  const paginator = paginateScan({client}, params);

  let pageCount = 0;

  for await (const page of paginator) {
    pageCount++;
    console.log(`Page ${pageCount}, Items:`, page.Items);
  }
}

paginatedScanUsingPaginator().catch((err) => {
  console.error(err);
});
```

**nota**  
Realizar verificações de tabela completas regularmente não é um padrão de acesso recomendado, a menos que a tabela seja pequena.

## Especificar a configuração
<a name="programming-with-javascript-config"></a>

**Topics**
+ [Configuração de tempos limite](#programming-with-javascript-config-timeouts)
+ [Configuração de keep-alive](#programming-with-javascript-config-keep-alive)
+ [Configuração de novas tentativas](#programming-with-javascript-config-retries)

Ao configurar o `DynamoDBClient`, é possível especificar várias substituições de configuração transmitindo um objeto de configuração para o construtor. Por exemplo, é possível especificar a região à qual se conectar se ela ainda não for conhecida pelo contexto da chamada ou pelo URL do endpoint a ser usado. Isso será útil se você quiser visar a uma instância do DynamoDB Local para fins de desenvolvimento.

```
const client = new DynamoDBClient({
  region: "eu-west-1",
  endpoint: "http://localhost:8000",
});
```

### Configuração de tempos limite
<a name="programming-with-javascript-config-timeouts"></a>

O DynamoDB usa HTTPS para a comunicação cliente-servidor. É possível controlar alguns aspectos da camada HTTP fornecendo um objeto `NodeHttpHandler`. Por exemplo, é possível ajustar os valores de tempo limite principais `connectionTimeout` e `requestTimeout`. O `connectionTimeout` é a duração máxima, em milissegundos, que o cliente aguardará ao tentar estabelecer uma conexão antes de desistir.

O `requestTimeout` define quanto tempo o cliente aguardará por uma resposta após o envio de uma solicitação, também em milissegundos. Os padrões para ambos são zero, o que significa que o tempo limite está desabilitado e não há limite de quanto tempo o cliente esperará se a resposta não chegar. É necessário definir os tempos limite para algo razoável para que, no caso de um problema de rede, a solicitação seja encerrada com um erro e uma nova solicitação possa ser iniciada. Por exemplo:

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { NodeHttpHandler } from "@smithy/node-http-handler";

const requestHandler = new NodeHttpHandler({
  connectionTimeout: 2000,
  requestTimeout: 2000,
});

const client = new DynamoDBClient({
  requestHandler
});
```

**nota**  
O exemplo fornecido usa a importação [Smithy.](https://smithy.io/2.0/index.html) Smithy é uma linguagem que define serviços e SDKs, é de código aberto e mantida pela AWS.

Além de configurar valores de tempo limite, você pode definir o número máximo de soquetes, o que permite um maior número de conexões simultâneas por origem. O guia do desenvolvedor inclui [detalhes sobre a configuração do parâmetro `maxSockets`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-configuring-maxsockets.html).

### Configuração de keep-alive
<a name="programming-with-javascript-config-keep-alive"></a>

Ao usar HTTPS, a primeira solicitação sempre exige alguma comunicação de ida e volta para estabelecer uma conexão segura. O HTTP Keep-Alive permite que solicitações subsequentes reutilizem a conexão já estabelecida, tornando as solicitações mais eficientes e reduzindo a latência. O HTTP Keep-Alive está habilitado por padrão com o JavaScript V3. 

Há um limite de quanto tempo uma conexão inativa pode ser mantida ativa. Pense em enviar solicitações periódicas, talvez a cada minuto, se tiver uma conexão ociosa, mas quiser que a próxima solicitação use uma conexão já estabelecida.

**nota**  
Observe que na V2 antiga do SDK, o keep-alive estava desativado por padrão, o que significa que cada conexão seria fechada imediatamente após o uso. Se estiver usando a V2, poderá substituir essa configuração.

### Configuração de novas tentativas
<a name="programming-with-javascript-config-retries"></a>

Quando o SDK recebe uma resposta de erro e o erro pode ser exibido conforme determinado pelo SDK, como uma exceção de controle de utilização ou uma exceção de serviço temporário, ele tentará novamente. Isso acontece de forma invisível para você como chamador, exceto que você note que a solicitação demorou mais para ser bem-sucedida.

O SDK para JavaScript V3 fará três solicitações no total, por padrão, antes de desistir e transmitir o erro para o contexto de chamada. É possível ajustar o número e a frequência dessas novas tentativas.

O construtor `DynamoDBClient` aceita uma configuração `maxAttempts` que limita quantas tentativas acontecerão. O exemplo abaixo eleva o valor do padrão de três para um total de cinco. Se você defini-lo como 0 ou 1, isso indica que você não quer nenhuma nova tentativa automática e quer lidar com quaisquer erros retomáveis no bloco Catch.

```
const client = new DynamoDBClient({
  maxAttempts: 5,
});
```

Também é possível controlar o tempo das novas tentativas com uma estratégia de repetição personalizada. Para fazer isso, importe o pacote de utilitários `util-retry` e crie uma função de recuo personalizada que calcule o tempo de espera entre as novas tentativas com base na contagem atual delas.

O exemplo abaixo determina no máximo cinco tentativas com atrasos de 15, 30, 90 e 360 milissegundos caso a primeira tentativa falhe. A função de recuo personalizada, ` calculateRetryBackoff`, calcula os atrasos aceitando o número de novas tentativas (começa com 1 na primeira tentativa) e exibe quantos milissegundos esperar por essa solicitação.

```
const { ConfiguredRetryStrategy } = require("@aws-sdk/util-retry");

const calculateRetryBackoff = (attempt) => {
  const backoffTimes = [15, 30, 90, 360];
  return backoffTimes[attempt - 1] || 0;
};

const client = new DynamoDBClient({
  retryStrategy: new ConfiguredRetryStrategy(
    5, // max attempts.
    calculateRetryBackoff // backoff function.
  ),
});
```

## Waiters
<a name="programming-with-javascript-waiters"></a>

O cliente do DynamoDB inclui duas [funções waiter](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/wait/index.html#cli-aws-dynamodb-wait) úteis que podem ser usadas ao criar, modificar ou excluir tabelas quando você quiser que o código espere até que a modificação da tabela seja concluída. Por exemplo, é possível implantar uma tabela, chamar a função `waitUntilTableExists` e o código será bloqueado até que a tabela se torne **ATIVA**. O waiter pesquisa internamente o serviço do DynamoDB com uma `describe-table` a cada vinte segundos.

```
import {waitUntilTableExists, waitUntilTableNotExists} from "@aws-sdk/client-dynamodb";

… <create table details>

const results = await waitUntilTableExists({client: client, maxWaitTime: 180}, {TableName: "products"});
if (results.state == 'SUCCESS') {
  return results.reason.Table
}
console.error(`${results.state} ${results.reason}`);
```

O recurso `waitUntilTableExists` retorna o controle somente quando pode executar um comando `describe-table` que mostra o status da tabela **ATIVO**. Isso garante que você possa usar `waitUntilTableExists` para aguardar a conclusão da criação, bem como modificações, como adicionar um índice GSI, que pode levar algum tempo para ser aplicado antes que a tabela retorne ao status **ATIVO**.

## Tratamento de erros
<a name="programming-with-javascript-error-handling"></a>

Nos primeiros exemplos aqui, detectamos todos os erros de forma ampla. No entanto, em aplicações práticas, é importante discernir entre vários tipos de erros e implementar um tratamento de erros mais preciso.

As respostas de erro do DynamoDB contêm metadados, incluindo o nome do erro. É possível capturar erros e, depois, comparar os possíveis nomes de string das condições de erro para determinar como proceder. Sobre erros do lado do servidor, é possível utilizar o operador `instanceof` com os tipos de erro exportados pelo pacote `@aws-sdk/client-dynamodb` para gerenciar o tratamento de erros com eficiência.

É importante observar que esses erros só se manifestam após o esgotamento de todas as novas tentativas. Se um erro for repetido e, por fim, seguido por uma chamada bem-sucedida, do ponto de vista do código, não haverá erro, apenas uma latência ligeiramente elevada. As novas tentativas aparecerão nos gráficos do Amazon CloudWatch como solicitações malsucedidas, como solicitações de controle de utilização ou erro. Se o cliente atingir a contagem máxima de novas tentativas, ele desistirá e gerará uma exceção. Essa é a maneira de o cliente dizer que não vai tentar novamente.

Veja abaixo um trecho que captura o erro e age com base no tipo de erro que foi exibido.

```
import {
  ResourceNotFoundException
  ProvisionedThroughputExceededException,
  DynamoDBServiceException,
} from "@aws-sdk/client-dynamodb";

try {
  await client.send(someCommand);
} catch (e) {
    if (e instanceof ResourceNotFoundException) {
      // Handle ResourceNotFoundException
    } else if (e instanceof ProvisionedThroughputExceededException) {
      // Handle ProvisionedThroughputExceededException
    } else if (e instanceof DynamoDBServiceException) {
      // Handle DynamoDBServiceException
    } else {
      // Other errors such as those from the SDK
      if (e.name === "TimeoutError") {
        // Handle SDK TimeoutError.
      } else {
        // Handle other errors.
      }
    }
}
```

Consulte [Tratamento de erros com o DynamoDB](Programming.Errors.md) para ver as strings de erro comuns no *Guia do desenvolvedor do DynamoDB*. Os erros exatos possíveis com qualquer chamada de API específica podem ser encontrados na documentação dessa chamada de API, como os [documentos da API Query.](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html)

Os metadados dos erros incluem propriedades adicionais, dependendo do erro. Para ` TimeoutError`, os metadados incluem o número de tentativas que foram feitas e o `totalRetryDelay`, conforme mostrado abaixo.

```
{
  "name": "TimeoutError",
  "$metadata": {
    "attempts": 3,
    "totalRetryDelay": 199
  }
}
```

Se você gerencia sua própria política de novas tentativas, convém diferenciar entre controles de utilização e erros:
+ Um **controle de utilização** (designado por um ` ProvisionedThroughputExceededException` ou `ThrottlingException`) indica um serviço íntegro que está informando que você excedeu sua capacidade de leitura ou gravação em uma tabela ou partição do DynamoDB. A cada milissegundo que se passa, um pouco mais de capacidade de leitura ou gravação é disponibilizada e, portanto, é possível tentar acessar essa capacidade recém-liberada rapidamente; por exemplo, a cada 50 ms.

   Com os controles de utilização, não é especialmente necessário um recuo exponencial porque os controles de utilização são leves para o DynamoDB exibir e não cobram por solicitação. O recuo exponencial atribui atrasos maiores aos threads do cliente que já esperaram por mais tempo, o que estende estatisticamente o p50 e o p99.
+ Um **erro** (designado por um ` InternalServerError` ou `ServiceUnavailable`, entre outros) indica um problema transitório com o serviço, possivelmente com a tabela inteira ou apenas com a partição que você está lendo ou na qual está gravando. Com erros, é possível pausar por mais tempo antes de novas tentativas, como 250 ms ou 500 ms, e usar a instabilidade para escalonar as novas tentativas.

## Registro em log
<a name="programming-with-javascript-logging"></a>

Ative o registro em log para ter mais detalhes sobre o que o SDK está fazendo. É possível definir um parâmetro no `DynamoDBClient` conforme exibido no exemplo abaixo. Mais informações de log aparecerão no console e incluirão metadados, como o código de status e a capacidade consumida. Se você executar o código localmente em uma janela de terminal, os logs aparecerão lá. Se você executar o código no AWS Lambda e tiver o Amazon CloudWatch Logs configurado, a saída do console será gravada lá.

```
const client = new DynamoDBClient({
  logger: console
});
```

Também é possível se conectar às atividades internas do SDK e realizar o registro em log personalizado à medida que determinados eventos acontecem. O exemplo abaixo usa a `middlewareStack` do cliente para interceptar cada solicitação à medida que ela é enviada do SDK e a registra em log enquanto ela está acontecendo.

```
const client = new DynamoDBClient({});

client.middlewareStack.add(
  (next) => async (args) => {
    console.log("Sending request from AWS SDK", { request: args.request });
    return next(args);
  },
  {
    step: "build",
    name: "log-ddb-calls",
  }
);
```

A `MiddlewareStack` fornece um hook avançado para observar e controlar o comportamento do SDK. Consulte o blog [Introducing Middleware Stack in Modular AWS SDK para JavaScript](https://aws.amazon.com/blogs/developer/middleware-stack-modular-aws-sdk-js/) para ter mais informações.

## Considerações
<a name="programming-with-javascript-considerations"></a>

Ao implementar o AWS SDK para JavaScript em seu projeto, veja a seguir alguns outros fatores a serem considerados.

**Sistemas de módulos**  
O SDK comporta dois sistemas de módulos, CommonJS e ES (ECMAScript). O CommonJS usa a função `require`, enquanto o ES usa a palavra-chave `import`.  

1. **Common JS** – `const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");`

1. **ES (ECMAScript** – `import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";`
O tipo de projeto determina o sistema de módulos a ser usado e é especificado na seção de tipos do arquivo package.json. O padrão é CommonJS. Use `"type": "module"` para indicar um projeto ES. Se você tiver um projeto Node.js que use o formato de pacote CommonJS, ainda poderá adicionar funções com a sintaxe mais moderna do SDK V3 Import nomeando seus arquivos de função com a extensão .mjs. Isso permitirá que o arquivo de código seja tratado como ES (ECMAScript).

**Operações assíncronas**  
Você verá muitos exemplos de código usando retornos de chamada e promessas para lidar com o resultado das operações do DynamoDB. Com o JavaScript moderno, essa complexidade não é mais necessária e os desenvolvedores podem aproveitar a sintaxe async/await mais sucinta e legível para operações assíncronas.

**Runtime de navegador da web**  
Desenvolvedores web e para dispositivos móveis que criam com React ou React Native podem usar o SDK para JavaScript nos projetos. Com a V2 anterior do SDK, os desenvolvedores web precisariam carregar o SDK completo no navegador, fazendo referência a uma imagem do SDK hospedada em https://sdk.amazonaws.com/js/.   
Com a V3, é possível empacotar apenas os módulos de cliente V3 necessários e todas as funções do JavaScript necessárias em um único arquivo JavaScript que usa Webpack e adicioná-lo a uma tag do script no `<head>` de suas páginas HTML, conforme explicado na seção [Conceitos básicos de um script de navegador](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-started-browser.html) da documentação do SDK.

**Operações do plano de dados do DAX**  
O SDK para JavaScript V3 agora comporta operações de plano de dados do Amazon DynamoDB Streams Accelerator (DAX).

# Programar o DynamoDB com o AWS SDK for Java 2.x
<a name="ProgrammingWithJava"></a>

Este guia de programação fornece uma orientação para programadores que desejam usar o Amazon DynamoDB com Java. O guia aborda diversos conceitos, incluindo camadas de abstração, gerenciamento de configurações, tratamento de erros, controle de políticas de novas tentativas e gerenciamento de keep-alive.

**Topics**
+ [Sobre o AWS SDK for Java 2.x](#AboutProgrammingWithJavaSDK)
+ [Introdução](#GetStartedProgrammingWithJavaSDK)
+ [Documentação do SDK para Java 2.x](#ProgrammingWithJavaUseDoc)
+ [Interfaces compatíveis](#JavaInterfaces)
+ [Exemplos de código adicionais](#AdditionalCodeEx)
+ [Programação sincronizada e assíncrona](#SyncAsyncProgramming)
+ [Clientes HTTP](#HttpClients)
+ [Config](#ConfigHttpClient)
+ [Tratamento de erros](#JavaErrorHandling)
+ [ID da solicitação da AWS](#JavaRequestID)
+ [Registro em log](#JavaLogging)
+ [Paginação](#JavaPagination)
+ [Anotações de classes de dados](#JavaDataClassAnnotation)

## Sobre o AWS SDK for Java 2.x
<a name="AboutProgrammingWithJavaSDK"></a>

É possível acessar o DynamoDB pelo Java usando o AWS SDK para Java oficial. O SDK para Java tem duas versões: 1.x e 2.x. O fim do suporte para a versão 1.x foi [anunciado](https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-java-v1-x-on-december-31-2025/) em 12 de janeiro de 2024. Ele entrará no modo de manutenção em 31 de julho de 2024 e o fim do suporte está previsto para 31 de dezembro de 2025. Para novos desenvolvimentos, é altamente recomendável que você use 2.x, que foi lançado pela primeira vez em 2018. Este guia é voltado exclusivamente para a versão 2.x e se concentra somente nas partes do SDK relevantes para o DynamoDB.

Para obter informações sobre manutenção e suporte para os SDKs da AWS, consulte [AWS SDK and Tools maintenance policy](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html) and [AWS SDKs and Tools version support matrix](https://docs.aws.amazon.com/sdkref/latest/guide/version-support-matrix.html) no *Guia de referência de SDKs e ferramentas da AWS*.

O AWS SDK for Java 2.x é uma importante reescrita do código base da versão 1.x. O SDK para Java 2.x oferece suporte aos recursos Java modernos, como a E/S sem bloqueio introduzida no Java 8. O SDK para Java 2.x também adiciona suporte a implementações de clientes HTTP conectáveis para oferecer maior flexibilidade de conexão de rede e opções de configuração.

Uma alteração notável entre o SDK para Java 1.x e o SDK para Java 2.x é o uso de um novo nome de pacote. O SDK do Java 1.x usa o nome do pacote `com.amazonaws`, enquanto o SDK do Java 2.x usa `software.amazon.awssdk`. Da mesma forma, os artefatos do Maven do SDK para Java 1.x usam o `groupId` `com.amazonaws`, enquanto os artefatos do SDK para Java 2.x usam o `groupId` `software.amazon.awssdk`.

**Importante**  
O AWS SDK para Java 1.x tem um pacote do DynamoDB chamado `com.amazonaws.dynamodbv2`. A descrição “v2" no nome do pacote não indica que é destinado ao Java 2 (J2SE). Em vez disso, “v2" indica que o pacote é compatível com a [segunda versão](CurrentAPI.md) da API de baixo nível do DynamoDB em vez da [versão original](Appendix.APIv20111205.md) da API de baixo nível.

### Compatibilidade com versões do Java
<a name="SupportedJavaVersions"></a>

O AWS SDK for Java 2.x é totalmente compatível com [versões do Java](https://github.com/aws/aws-sdk-java-v2?tab=readme-ov-file#maintenance-and-support-for-java-versions) de suporte de longo prazo (LTS).

## Conceitos básicos da AWS SDK for Java 2.x
<a name="GetStartedProgrammingWithJavaSDK"></a>

O tutorial a seguir mostra como usar o [Apache Maven](https://maven.apache.org/) para definir dependências do SDK para Java 2.x. Este tutorial também mostra como escrever o código que se conecta ao DynamoDB para listar as tabelas disponíveis do DynamoDB. O tutorial deste guia é baseado no tutorial [Get started with the AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html) do *Guia do desenvolvedor do AWS SDK for Java 2.x*. Editamos esse tutorial para fazer chamadas para o DynamoDB e não para o Amazon S3.

**Topics**
+ [Etapa 1: configurar para este tutorial](#GetStartedJavaSetup)
+ [Etapa 2: criar o projeto](#GetStartedJavaProjectSetup)
+ [Etapa 3: escrever o código](#GetStartedJavaCode)
+ [Etapa 4: compilar e executar o aplicativo](#GetStartedRunJava)

### Etapa 1: configurar para este tutorial
<a name="GetStartedJavaSetup"></a>

Antes de iniciar este tutorial, é necessário instalar o seguinte:
+ Permissão para acessar o DynamoDB.
+ Um ambiente de desenvolvimento Java configurado com acesso de autenticação única aos Serviços da AWS usando o Portal de acesso da AWS.

Para se preparar para este tutorial, siga as instruções em [Setup overview](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-overview) no *Guia do desenvolvedor do AWS SDK for Java 2.x*. Depois de [configurar seu ambiente de desenvolvimento com acesso de autenticação única](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-credentials) para o SDK do Java e ter uma [sessão ativa do portal de acesso da AWS](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-login-sso), continue com a [Etapa 2](#GetStartedJavaProjectSetup) deste tutorial.

### Etapa 2: criar o projeto
<a name="GetStartedJavaProjectSetup"></a>

Para criar o projeto para este tutorial, você executa um comando do Maven que solicita informações sobre como configurar o projeto. Depois que todas as informações forem inseridas e confirmadas, o Maven concluirá a construção do projeto criando um arquivo `pom.xml` e criará arquivos Java stub.

1. Abra uma janela de terminal ou prompt de comando e navegue até um diretório de sua escolha, por exemplo, sua pasta `Desktop` ou `Home`.

1. Insira o comando a seguir no terminal e pressione **Enter**.

   ```
   mvn archetype:generate \
      -DarchetypeGroupId=software.amazon.awssdk \
      -DarchetypeArtifactId=archetype-app-quickstart \
      -DarchetypeVersion=2.22.0
   ```

1. Para cada prompt, insira o valor listado na segunda coluna.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/ProgrammingWithJava.html)

1. Depois de inserir o último valor, o Maven lista as escolhas que você fez. Para confirmar, insira **Y**. Ou insira **N** e suas opções novamente.

O Maven cria uma pasta de projeto chamada `getstarted` com base no valor de `artifactId` que você informou. Dentro da pasta `getstarted`, encontre um arquivo chamado `README.md` que você possa revisar, um arquivo `pom.xml` e um diretório `src`.

O Maven cria a árvore de diretórios a seguir.

```
getstarted
 ├── README.md
 ├── pom.xml
 └── src
     ├── main
     │   ├── java
     │   │   └── org
     │   │       └── example
     │   │           ├── App.java
     │   │           ├── DependencyFactory.java
     │   │           └── Handler.java
     │   └── resources
     │       └── simplelogger.properties
     └── test
         └── java
             └── org
                 └── example
                     └── HandlerTest.java
 
 10 directories, 7 files
```

O exemplo a seguir mostra o conteúdo do arquivo de projeto `pom.xml`.

#### `pom.xml`
<a name="ProjectSetupCollapse2"></a>

A seção `dependencyManagement` contém uma dependência do AWS SDK for Java 2.x e a seção `dependencies` tem uma dependência do DynamoDB. A especificação dessas dependências força o Maven a incluir os arquivos `.jar` relevantes no caminho da classe Java. Por padrão, o SDK da AWS não inclui todas as classes para todos os Serviços da AWS. Para o DynamoDB, se você usar a interface de baixo nível, deverá ter uma dependência no artefato `dynamodb`. Se você usar a interface de alto nível, a dependência deverá estar no artefato `dynamodb-enhanced`. Se você não incluir as dependências relevantes, o código não será compilado. O projeto usa o Java 1.8 devido ao valor `1.8` nas propriedades `maven.compiler.source` e `maven.compiler.target`.

```
<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>org.example</groupId>
     <artifactId>getstarted</artifactId>
     <version>1.0-SNAPSHOT</version>
     <packaging>jar</packaging>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
         <maven.shade.plugin.version>3.2.1</maven.shade.plugin.version>
         <maven.compiler.plugin.version>3.6.1</maven.compiler.plugin.version>
         <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
         <aws.java.sdk.version>2.22.0</aws.java.sdk.version> <-------- SDK version picked up from archetype version.
         <slf4j.version>1.7.28</slf4j.version>
         <junit5.version>5.8.1</junit5.version>
     </properties>
 
     <dependencyManagement>
         <dependencies>
             <dependency>
                 <groupId>software.amazon.awssdk</groupId>
                 <artifactId>bom</artifactId>
                 <version>${aws.java.sdk.version}</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
         </dependencies>
     </dependencyManagement>
 
     <dependencies>
         <dependency>
             <groupId>software.amazon.awssdk</groupId>
             <artifactId>dynamodb</artifactId>  <-------- DynamoDB dependency
             <exclusions>
                 <exclusion>
                     <groupId>software.amazon.awssdk</groupId>
                     <artifactId>netty-nio-client</artifactId>
                 </exclusion>
                 <exclusion>
                     <groupId>software.amazon.awssdk</groupId>
                     <artifactId>apache-client</artifactId>
                 </exclusion>
             </exclusions>
         </dependency>
 
         <dependency>
             <groupId>software.amazon.awssdk</groupId>
             <artifactId>sso</artifactId> <-------- Required for identity center authentication.
         </dependency>
 
         <dependency>
             <groupId>software.amazon.awssdk</groupId>
             <artifactId>ssooidc</artifactId> <-------- Required for identity center authentication.
         </dependency>
 
         <dependency>
             <groupId>software.amazon.awssdk</groupId>
             <artifactId>apache-client</artifactId> <-------- HTTP client specified.
             <exclusions>
                 <exclusion>
                     <groupId>commons-logging</groupId>
                     <artifactId>commons-logging</artifactId>
                 </exclusion>
             </exclusions>
         </dependency>
 
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>${slf4j.version}</version>
         </dependency>
 
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-simple</artifactId>
             <version>${slf4j.version}</version>
         </dependency>
 
         <!-- Needed to adapt Apache Commons Logging used by Apache HTTP Client to Slf4j to avoid
         ClassNotFoundException: org.apache.commons.logging.impl.LogFactoryImpl during runtime -->
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl-over-slf4j</artifactId>
             <version>${slf4j.version}</version>
         </dependency>
 
         <!-- Test Dependencies -->
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
             <version>${junit5.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
 
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>${maven.compiler.plugin.version}</version>
             </plugin>
         </plugins>
     </build>
 
 </project>
```

### Etapa 3: escrever o código
<a name="GetStartedJavaCode"></a>

O código a seguir mostra a classe `App` criada pelo Maven. O método `main` é o ponto de entrada no aplicativo, que cria uma instância da classe `Handler` e, em seguida, chama seu método `sendRequest`.

#### `App`Classe
<a name="projectsetup-collapse2"></a>

```
package org.example;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class App {
     private static final Logger logger = LoggerFactory.getLogger(App.class);
 
     public static void main(String... args) {
         logger.info("Application starts");
 
         Handler handler = new Handler();
         handler.sendRequest();
 
         logger.info("Application ends");
     }
 }
```

A classe `DependencyFactory` criada pelo Maven contém o método de fábrica `dynamoDbClient`, que cria e exibe uma instância de [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html). A instância do `DynamoDbClient` usa uma instância do cliente HTTP baseado em Apache. Isso ocorre porque você especificou `apache-client` quando o Maven solicitou o cliente HTTP a ser usado.

O código a seguir mostra a classe `DependencyFactory`.

#### Classe DependencyFactory
<a name="code-collapse2"></a>

```
package org.example;
 
 import software.amazon.awssdk.http.apache.ApacheHttpClient;
 import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
 
 /**
  * The module containing all dependencies required by the {@link Handler}.
  */
 public class DependencyFactory {
 
     private DependencyFactory() {}
 
     /**
      * @return an instance of DynamoDbClient
      */
     public static DynamoDbClient dynamoDbClient() {
         return DynamoDbClient.builder()
                        .httpClientBuilder(ApacheHttpClient.builder())
                        .build();
     }
 }
```

A classe `Handler` contém a lógica principal do seu programa. Quando uma instância de `Handler` é criada na classe `App`, a classe `DependencyFactory` fornece o cliente de serviço do `DynamoDbClient`. O código usa a instância de `DynamoDbClient` para chamar o DynamoDB.

O Maven gera a seguinte classe `Handler` com um comentário `TODO`. A próxima etapa do tutorial substitui o comentário *`TODO`* pelo código.

#### Classe `Handler`, gerada pelo Maven
<a name="code-collapsible3"></a>

```
package org.example;
 
 import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
 
 
 public class Handler {
     private final DynamoDbClient dynamoDbClient;
 
     public Handler() {
         dynamoDbClient = DependencyFactory.dynamoDbClient();
     }
 
     public void sendRequest() {
         // TODO: invoking the API calls using dynamoDbClient.
     }
 }
```

Para preencher a lógica, substitua todo o conteúdo da classe `Handler` pelo código a seguir. O método `sendRequest` é preenchido e as importações necessárias são adicionadas.

#### Classe `Handler`, implementada
<a name="code-collapse4"></a>

O código a seguir usa a instância [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html) para recuperar uma lista das tabelas existentes. Se existirem tabelas para uma conta e Região da AWS, o código usará a instância de `Logger` para registrar em log os nomes dessas tabelas.

```
package org.example;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
 import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse;
 
 
 public class Handler {
     private final DynamoDbClient dynamoDbClient;
 
     public Handler() {
         dynamoDbClient = DependencyFactory.dynamoDbClient();
     }
 
     public void sendRequest() {
         Logger logger = LoggerFactory.getLogger(Handler.class);
 
         logger.info("calling the DynamoDB API to get a list of existing tables");
         ListTablesResponse response = dynamoDbClient.listTables();
 
         if (!response.hasTableNames()) {
             logger.info("No existing tables found for the configured account & region");
         } else {
             response.tableNames().forEach(tableName -> logger.info("Table: " + tableName));
         }
     }
 }
```

### Etapa 4: compilar e executar o aplicativo
<a name="GetStartedRunJava"></a>

Depois que o projeto for criado e contiver a classe `Handler` completa, crie e execute a aplicação.

1. Garanta que você tenha uma sessão ativa do Centro de Identidade do AWS IAM. Para confirmar, execute o comando `aws sts get-caller-identity` da AWS Command Line Interface (AWS CLI) e verifique a resposta. Se você não tiver uma sessão ativa, consulte [Sign in using the AWS CLI](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-login-sso) para obter instruções.

1. Abra uma janela de terminal ou prompt de comando e navegue até o diretório `getstarted` do seu projeto.

1. Para compilar seu projeto, execute o seguinte comando:

   ```
   mvn clean package
   ```

1. Para executar a aplicação, execute o seguinte comando:

   ```
   mvn exec:java -Dexec.mainClass="org.example.App"
   ```

Depois de visualizar o arquivo, exclua o objeto e, em seguida, exclua o bucket.

#### Bem-sucedida
<a name="GetStartedSuccessJava"></a>

Se seu projeto Maven foi criado e executado sem erros, parabéns\$1 Você compilou com sucesso sua primeira aplicação Java usando o SDK para Java 2.x.

#### Limpeza
<a name="GetStartedCleanupJava"></a>

Para limpar os recursos que foram criados durante este tutorial, exclua a pasta de projeto `getstarted`.

## Analisar a documentação do AWS SDK for Java 2.x
<a name="ProgrammingWithJavaUseDoc"></a>

O [Guia do desenvolvedor do AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html) abrange todos os aspectos do SDK em todos os Serviços da AWS. Recomendamos que você analise os seguintes tópicos:
+ [Migrate from version 1.x to 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html): inclui uma explicação detalhada das diferenças entre as versões 1.x e 2.x. Esse tópico também contém instruções sobre como usar as duas versões principais lado a lado.
+ [DynamoDB guide for Java 2.x SDK](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/examples-dynamodb.html): mostra como realizar operações básicas do DynamoDB, incluindo criação de tabelas e tratamento e recuperação de itens. Esses exemplos usam a interface de nível inferior. O Java tem várias interfaces, conforme explicado na seguinte seção: [Interfaces compatíveis](#JavaInterfaces).

**dica**  
Depois de analisar esses tópicos, adicione a [Referência de API do AWS SDK for Java 2.x](https://sdk.amazonaws.com/java/api/latest/) aos favoritos. Ela abrange todos os Serviços da AWS e recomendamos que você utilize-a como principal referência de API.

## Interfaces compatíveis
<a name="JavaInterfaces"></a>

O AWS SDK for Java 2.x oferece suporte às interfaces a seguir, dependendo do nível de abstração desejado.

**Topics**
+ [Interface de nível inferior](#LowLevelInterface)
+ [Interfaces de alto nível](#HighLevelInterface)
+ [Interface Document](#DocumentInterface)
+ [Comparar interfaces com um exemplo de `Query`](#CompareJavaInterfacesQueryEx)

### Interface de nível inferior
<a name="LowLevelInterface"></a>

A interface de nível inferior fornece um mapeamento individual para a API de serviço subjacente. Cada API do DynamoDB está disponível por meio dessa interface. Isso significa que a interface de baixo nível pode fornecer funcionalidade completa, mas geralmente é mais detalhada e complexa de usar. Por exemplo, você precisa usar as funções `.s()` para armazenar strings e as funções `.n()` para armazenar números. O exemplo a seguir de [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) insere um item usando a interface de nível inferior.

```
import org.slf4j.*;
import software.amazon.awssdk.http.crt.AwsCrtHttpClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.util.Map;

public class PutItem {

    // Create a DynamoDB client with the default settings connected to the DynamoDB
    // endpoint in the default region based on the default credentials provider chain.
    private static final DynamoDbClient DYNAMODB_CLIENT = DynamoDbClient.create();
    private static final Logger LOGGER = LoggerFactory.getLogger(PutItem.class);

    private void putItem() {
        PutItemResponse response = DYNAMODB_CLIENT.putItem(PutItemRequest.builder()
                .item(Map.of(
                        "pk", AttributeValue.builder().s("123").build(),
                        "sk", AttributeValue.builder().s("cart#123").build(),
                        "item_data", AttributeValue.builder().s("YourItemData").build(),
                        "inventory", AttributeValue.builder().n("500").build()
                        // ... more attributes ...
                ))
                .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
                .tableName("YourTableName")
                .build());
        LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)");
    }
}
```

### Interfaces de alto nível
<a name="HighLevelInterface"></a>

A interface de alto nível no AWS SDK for Java 2.x é chamada de cliente aprimorado do DynamoDB. Essa interface oferece uma experiência de criação de código mais idiomática.

O cliente aprimorado oferece uma forma de associar classes de dados do lado do cliente e tabelas do DynamoDB projetadas para armazenar esses dados. Basta definir as relações entre as tabelas e suas classes de modelo correspondentes no seu código. Depois, você pode recorrer ao SDK para gerenciar o tratamento do tipo de dados. Para obter mais informações sobre o cliente aprimorado, consulte [DynamoDB enhanced client API](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

O exemplo a seguir de [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) usa a interface de alto nível. Neste exemplo, o `DynamoDbBean` denominado `YourItem` cria um `TableSchema` que permite seu uso direto como entrada para a chamada `putItem()`.

```
import org.slf4j.*;
import software.amazon.awssdk.enhanced.dynamodb.*;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*;
import software.amazon.awssdk.enhanced.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;

public class DynamoDbEnhancedClientPutItem {
    private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build();
    private static final DynamoDbTable<YourItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromBean(YourItem.class));
    private static final Logger LOGGER = LoggerFactory.getLogger(PutItem.class);

    private void putItem() {
        PutItemEnhancedResponse<YourItem> response = DYNAMODB_TABLE.putItemWithResponse(PutItemEnhancedRequest.builder(YourItem.class)
                .item(new YourItem("123", "cart#123", "YourItemData", 500))
                .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
                .build());
        LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)");
    }

    @DynamoDbBean
    public static class YourItem {

        public YourItem() {}

        public YourItem(String pk, String sk, String itemData, int inventory) {
            this.pk = pk;
            this.sk = sk;
            this.itemData = itemData;
            this.inventory = inventory;
        }

        private String pk;
        private String sk;
        private String itemData;

        private int inventory;

        @DynamoDbPartitionKey
        public void setPk(String pk) {
            this.pk = pk;
        }

        public String getPk() {
            return pk;
        }

        @DynamoDbSortKey
        public void setSk(String sk) {
            this.sk = sk;
        }

        public String getSk() {
            return sk;
        }

        public void setItemData(String itemData) {
            this.itemData = itemData;
        }

        public String getItemData() {
            return itemData;
        }

        public void setInventory(int inventory) {
            this.inventory = inventory;
        }

        public int getInventory() {
            return inventory;
        }
    }
}
```

O AWS SDK para Java 1.x tem sua própria interface de alto nível, que geralmente é chamada pela sua classe principal `DynamoDBMapper`. O AWS SDK for Java 2.x é publicado em um pacote separado (e artefato do Maven) chamado `software.amazon.awssdk.enhanced.dynamodb`. O SDK do Java 2.x geralmente é chamado por sua classe principal `DynamoDbEnhancedClient`.

#### Interface de alto nível usando classes de dados imutáveis
<a name="HighLevelInterfaceImmutableDataClasses"></a>

O recurso de mapeamento da API do cliente aprimorado do DynamoDB funciona com classes de dados imutáveis. Uma classe imutável tem apenas getters e requer uma classe construtora que o SDK usa para criar instâncias da classe. A imutabilidade em Java é um estilo comumente utilizado que os desenvolvedores podem usar para criar classes sem efeitos secundários. Essas classes apresentam comportamento mais previsível em aplicações multithread complexas. Em vez de usar a anotação `@DynamoDbBean` conforme mostrado na [High-level interface example](#highleveleg), as classes imutáveis usam a anotação `@DynamoDbImmutable`, que utiliza a classe de construtor como sua entrada.

O exemplo a seguir usa a classe do construtor `DynamoDbEnhancedClientImmutablePutItem` como entrada para criar um esquema de tabela. Depois, o exemplo fornece o esquema como entrada para a chamada de API [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html).

```
import org.slf4j.*;
import software.amazon.awssdk.enhanced.dynamodb.*;
import software.amazon.awssdk.enhanced.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;

public class DynamoDbEnhancedClientImmutablePutItem {
    private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build();
    private static final DynamoDbTable<YourImmutableItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromImmutableClass(YourImmutableItem.class));
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedClientImmutablePutItem.class);

    private void putItem() {
        PutItemEnhancedResponse<YourImmutableItem> response = DYNAMODB_TABLE.putItemWithResponse(PutItemEnhancedRequest.builder(YourImmutableItem.class)
                .item(YourImmutableItem.builder()
                                        .pk("123")
                                        .sk("cart#123")
                                        .itemData("YourItemData")
                                        .inventory(500)
                                        .build())
                .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
                .build());
        LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)");
    }
}
```

O exemplo a seguir mostra a classe de dados imutáveis.

```
@DynamoDbImmutable(builder = YourImmutableItem.YourImmutableItemBuilder.class)
class YourImmutableItem {
    private final String pk;
    private final String sk;
    private final String itemData;
    private final int inventory;
    public YourImmutableItem(YourImmutableItemBuilder builder) {
        this.pk = builder.pk;
        this.sk = builder.sk;
        this.itemData = builder.itemData;
        this.inventory = builder.inventory;
    }

    public static YourImmutableItemBuilder builder() { return new YourImmutableItemBuilder(); }

    @DynamoDbPartitionKey
    public String getPk() {
        return pk;
    }

    @DynamoDbSortKey
    public String getSk() {
        return sk;
    }

    public String getItemData() {
        return itemData;
    }

    public int getInventory() {
        return inventory;
    }

    static final class YourImmutableItemBuilder {
        private String pk;
        private String sk;
        private String itemData;
        private int inventory;

        private YourImmutableItemBuilder() {}

        public YourImmutableItemBuilder pk(String pk) { this.pk = pk; return this; }
        public YourImmutableItemBuilder sk(String sk) { this.sk = sk; return this; }
        public YourImmutableItemBuilder itemData(String itemData) { this.itemData = itemData; return this; }
        public YourImmutableItemBuilder inventory(int inventory) { this.inventory = inventory; return this; }

        public YourImmutableItem build() { return new YourImmutableItem(this); }
    }
}
```

#### Interface de alto nível usando classes de dados imutáveis e bibliotecas de geração de código clichê de terceiros
<a name="ImmutableDataClassesThirdPartyBoilerplateGenLib"></a>

As classes de dados imutáveis (mostradas no exemplo anterior) exigem código clichê. Por exemplo, as lógicas getter e setter nas classes de dados, além das classes `Builder`. Bibliotecas de terceiros, como [Project Lombok](https://projectlombok.org/), podem ajudar você a gerar esse tipo de código clichê. Reduzir a maior parte do código clichê ajuda a limitar a quantidade de código necessária para trabalhar com classes de dados imutáveis e com o SDK da AWS. Isso ocasiona ainda maior produtividade e legibilidade do código. Para obter mais informações, consulte [Use third-party libraries, such as Lombok](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-use-immut.html#ddb-en-client-use-immut-lombok) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

O exemplo a seguir demonstra como o Project Lombok simplifica o código necessário para usar a API do cliente aprimorado do DynamoDB.

```
import org.slf4j.*;
import software.amazon.awssdk.enhanced.dynamodb.*;
import software.amazon.awssdk.enhanced.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;

public class DynamoDbEnhancedClientImmutableLombokPutItem {

    private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build();
    private static final DynamoDbTable<YourImmutableLombokItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromImmutableClass(YourImmutableLombokItem.class));
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedClientImmutableLombokPutItem.class);

    private void putItem() {
        PutItemEnhancedResponse<YourImmutableLombokItem> response = DYNAMODB_TABLE.putItemWithResponse(PutItemEnhancedRequest.builder(YourImmutableLombokItem.class)
                .item(YourImmutableLombokItem.builder()
                        .pk("123")
                        .sk("cart#123")
                        .itemData("YourItemData")
                        .inventory(500)
                        .build())
                .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
                .build());
        LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)");
    }
}
```

O exemplo a seguir mostra o objeto de dados imutáveis da classe de dados imutáveis.

```
import lombok.*;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*;

@Builder
@DynamoDbImmutable(builder = YourImmutableLombokItem.YourImmutableLombokItemBuilder.class)
@Value
public class YourImmutableLombokItem {

    @Getter(onMethod_=@DynamoDbPartitionKey)
    String pk;
    @Getter(onMethod_=@DynamoDbSortKey)
    String sk;
    String itemData;
    int inventory;
}
```

A classe `YourImmutableLombokItem` usa as seguintes anotações fornecidas pelo Project Lombok e pelo SDK da AWS:
+ [@Builder](https://projectlombok.org/features/Builder): produz APIs de construtor complexas para classes de dados fornecidas pelo Project Lombok.
+ [@DynamoDbImmutable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/DynamoDbImmutable.html): identifica a classe `DynamoDbImmutable` como uma anotação de entidade mapeável do DynamoDB fornecida pelo SDK da AWS.
+ [@Value](https://projectlombok.org/features/Value): a variante imutável de `@Data`. Todos os campos são transformados em privados e definitivos por padrão, e os setters não são gerados. O Projeto Lombok fornece essa anotação.

### Interface Document
<a name="DocumentInterface"></a>

A interface Document do AWS SDK for Java 2.x evita a necessidade de especificar descritores de tipo de dados. Os tipos de dados estão implícitos pela semântica dos próprios dados. Essa interface Document é semelhante à interface Document do AWS SDK para Java 1.x, mas foi reformulada.

O [Document interface example](#DocInterfaceEg) a seguir mostra a chamada `PutItem` expressa usando a interface Document. O exemplo também usa EnhancedDocument. Para executar comandos em uma tabela do DynamoDB usando a API de documentos aprimorada, primeiro é necessário associar a tabela ao esquema da tabela de documentos para criar um objeto de recurso `DynamoDBTable`. O construtor de esquema de tabela Document requer uma chave de índice primária e provedores de conversão de atributos.

É possível usar `AttributeConverterProvider.defaultProvider()` para converter atributos de documentos de tipos padrão. Você pode alterar o comportamento padrão geral com uma implementação `AttributeConverterProvider` personalizada. Você também pode alterar o conversor para um único atributo. O [Guia de referência de SDKs e ferramentas da AWS](https://docs.aws.amazon.com/sdkref/latest/guide/version-support-matrix.html) fornece mais detalhes e exemplos sobre como usar conversores personalizados. O uso principal é para atributos de suas classes de domínio que não têm um conversor padrão disponível. Usando um conversor personalizado, é possível fornecer ao SDK as informações necessárias para gravação ou leitura no DynamoDB.

```
import org.slf4j.*;
import software.amazon.awssdk.enhanced.dynamodb.*;
import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument;
import software.amazon.awssdk.enhanced.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;

public class DynamoDbEnhancedDocumentClientPutItem {
    private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build();
    private static final DynamoDbTable<EnhancedDocument> DYNAMODB_TABLE =
            ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.documentSchemaBuilder()
                            .addIndexPartitionKey(TableMetadata.primaryIndexName(),"pk", AttributeValueType.S)
                            .addIndexSortKey(TableMetadata.primaryIndexName(), "sk", AttributeValueType.S)
                            .attributeConverterProviders(AttributeConverterProvider.defaultProvider())
                            .build());

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedDocumentClientPutItem.class);

    private void putItem() {
        PutItemEnhancedResponse<EnhancedDocument> response = DYNAMODB_TABLE.putItemWithResponse(
                        PutItemEnhancedRequest.builder(EnhancedDocument.class)
                                .item(
                                    EnhancedDocument.builder()
                                            .attributeConverterProviders(AttributeConverterProvider.defaultProvider())
                                            .putString("pk", "123")
                                            .putString("sk", "cart#123")
                                            .putString("item_data", "YourItemData")
                                            .putNumber("inventory", 500)
                                            .build())
                                .returnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
                                .build());
        LOGGER.info("PutItem call consumed [" + response.consumedCapacity().capacityUnits() + "] Write Capacity Unites (WCU)");
    }

}
```

Para converter documentos JSON de/em tipos de dados nativos do Amazon DynamoDB, você pode usar os seguintes métodos utilitários:
+ [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html#fromJson(java.lang.String)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html#fromJson(java.lang.String)): cria uma instância EnhancedDocument com base em uma string JSON.
+ [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html#toJson()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html#toJson()): cria uma representação de string JSON do documento que pode ser usada na aplicação como qualquer outro objeto JSON.

### Comparar interfaces com um exemplo de `Query`
<a name="CompareJavaInterfacesQueryEx"></a>

Esta seção mostra a mesma chamada [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) expressa usando as várias interfaces. Para ajustar os resultados dessas consultas, observe o seguinte:
+ O DynamoDB aponta para um valor específico de chave de partição, portanto você deve especificar a chave de partição inteira.
+ Para que a consulta aponte apenas para os itens do carrinho, a chave de classificação tem uma expressão de condição de chave que usa `begins_with`.
+ Usamos `limit()` para limitar a consulta a um máximo de cem itens devolvidos.
+ Definimos o `scanIndexForward` como falso. Os resultados são exibidos na ordem de bytes UTF-8, o que geralmente significa que o item de carrinho com o menor número é exibido primeiro. Ao definir `scanIndexForward` como falso, revertemos a ordem, e o item do carrinho com o maior número é exibido primeiro.
+ Aplicamos um filtro para remover qualquer resultado que não corresponda aos critérios. Os dados que estão sendo filtrados consomem capacidade de leitura, independentemente de o item corresponder ou não ao filtro.

**Example `Query` usando a interface de baixo nível**  
O exemplo a seguir consulta uma tabela chamada `YourTableName` usando um `keyConditionExpression`. Isso limita a consulta a um valor de chave de partição específico e a um valor de chave de classificação que começa com um valor de prefixo específico. Essas condições de chave limitam a quantidade de dados lidos do DynamoDB. Por fim, a consulta aplica um filtro aos dados recuperados do DynamoDB usando uma `filterExpression`.  

```
import org.slf4j.*;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.util.Map;

public class Query {

    // Create a DynamoDB client with the default settings connected to the DynamoDB 
    // endpoint in the default region based on the default credentials provider chain.
    private static final DynamoDbClient DYNAMODB_CLIENT = DynamoDbClient.builder().build();
    private static final Logger LOGGER = LoggerFactory.getLogger(Query.class);

    private static void query() {
        QueryResponse response = DYNAMODB_CLIENT.query(QueryRequest.builder()
                .expressionAttributeNames(Map.of("#name", "name"))
                .expressionAttributeValues(Map.of(
                    ":pk_val", AttributeValue.fromS("id#1"),
                    ":sk_val", AttributeValue.fromS("cart#"),
                    ":name_val", AttributeValue.fromS("SomeName")))
                .filterExpression("#name = :name_val")
                .keyConditionExpression("pk = :pk_val AND begins_with(sk, :sk_val)")
                .limit(100)
                .scanIndexForward(false)
                .tableName("YourTableName")
                .build());

        LOGGER.info("nr of items: " + response.count());
        LOGGER.info("First item pk: " + response.items().get(0).get("pk"));
        LOGGER.info("First item sk: " + response.items().get(0).get("sk"));
    }
}
```

**Example `Query` usando a interface Document**  
O exemplo a seguir consulta uma tabela chamada `YourTableName` usando a interface Document.  

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.enhanced.dynamodb.*;
import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument;
import software.amazon.awssdk.enhanced.dynamodb.model.*;

import java.util.Map;

public class DynamoDbEnhancedDocumentClientQuery {

    // Create a DynamoDB client with the default settings connected to the DynamoDB 
    // endpoint in the default region based on the default credentials provider chain.
    private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build();
    private static final DynamoDbTable<EnhancedDocument> DYNAMODB_TABLE =
            ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.documentSchemaBuilder()
                    .addIndexPartitionKey(TableMetadata.primaryIndexName(),"pk", AttributeValueType.S)
                    .addIndexSortKey(TableMetadata.primaryIndexName(), "sk", AttributeValueType.S)
                    .attributeConverterProviders(AttributeConverterProvider.defaultProvider())
                    .build());
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedDocumentClientQuery.class);

    private void query() {
        PageIterable<EnhancedDocument> response = DYNAMODB_TABLE.query(QueryEnhancedRequest.builder()
                .filterExpression(Expression.builder()
                        .expression("#name = :name_val")
                        .expressionNames(Map.of("#name", "name"))
                        .expressionValues(Map.of(":name_val", AttributeValue.fromS("SomeName")))
                        .build())
                .limit(100)
                .queryConditional(QueryConditional.sortBeginsWith(Key.builder()
                        .partitionValue("id#1")
                        .sortValue("cart#")
                        .build()))
                .scanIndexForward(false)
                .build());

        LOGGER.info("nr of items: " + response.items().stream().count());
        LOGGER.info("First item pk: " + response.items().iterator().next().getString("pk"));
        LOGGER.info("First item sk: " + response.items().iterator().next().getString("sk"));

    }
}
```

**Example `Query` usando a interface de alto nível**  
O exemplo a seguir consulta uma tabela chamada `YourTableName` usando a API do cliente aprimorado do DynamoDB.  

```
import org.slf4j.*;
import software.amazon.awssdk.enhanced.dynamodb.*;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*;
import software.amazon.awssdk.enhanced.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

import java.util.Map;

public class DynamoDbEnhancedClientQuery {

    private static final DynamoDbEnhancedClient ENHANCED_DYNAMODB_CLIENT = DynamoDbEnhancedClient.builder().build();
    private static final DynamoDbTable<YourItem> DYNAMODB_TABLE = ENHANCED_DYNAMODB_CLIENT.table("YourTableName", TableSchema.fromBean(DynamoDbEnhancedClientQuery.YourItem.class));
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDbEnhancedClientQuery.class);

    private void query() {
        PageIterable<YourItem> response = DYNAMODB_TABLE.query(QueryEnhancedRequest.builder()
                .filterExpression(Expression.builder()
                        .expression("#name = :name_val")
                        .expressionNames(Map.of("#name", "name"))
                        .expressionValues(Map.of(":name_val", AttributeValue.fromS("SomeName")))
                        .build())
                .limit(100)
                .queryConditional(QueryConditional.sortBeginsWith(Key.builder()
                        .partitionValue("id#1")
                        .sortValue("cart#")
                        .build()))
                .scanIndexForward(false)
                .build());

        LOGGER.info("nr of items: " + response.items().stream().count());
        LOGGER.info("First item pk: " + response.items().iterator().next().getPk());
        LOGGER.info("First item sk: " + response.items().iterator().next().getSk());
    }

    @DynamoDbBean
    public static class YourItem {

        public YourItem() {}

        public YourItem(String pk, String sk, String name) {
            this.pk = pk;
            this.sk = sk;
            this.name = name;
        }

        private String pk;
        private String sk;
        private String name;

        @DynamoDbPartitionKey
        public void setPk(String pk) {
            this.pk = pk;
        }

        public String getPk() {
            return pk;
        }

        @DynamoDbSortKey
        public void setSk(String sk) {
            this.sk = sk;
        }

        public String getSk() {
            return sk;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }
}
```
**Interface de alto nível usando classes de dados imutáveis**  
Quando você executa uma `Query` com as classes de dados imutáveis de alto nível, o código é o mesmo do exemplo de interface de alto nível, exceto pela construção da classe de entidade `YourItem` ou `YourImmutableItem`. Para ter mais informações, consulte o exemplo [PutItem](#HighLevelImmutableDataClassEg).
**Interface de alto nível usando classes de dados imutáveis e bibliotecas de geração de código clichê de terceiros**  
Quando você executa uma `Query` com as classes de dados imutáveis de alto nível, o código é o mesmo do exemplo de interface de alto nível, exceto pela construção da classe de entidade `YourItem` ou `YourImmutableLombokItem`. Para ter mais informações, consulte o exemplo [PutItem](#HighLevelImmutableDataClassEg).

## Exemplos de código adicionais
<a name="AdditionalCodeEx"></a>

Para conferir exemplos adicionais de como usar o DynamoDB com o SDK para Java 2.x, consulte os seguintes repositórios de exemplos de código:
+ [Exemplos oficiais de código de ação única da AWS](https://docs.aws.amazon.com/code-library/latest/ug/java_2_dynamodb_code_examples.html)
+ [Exemplos de códigos de ação única mantidos pela comunidade](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/java)
+ [Exemplos oficiais de código orientado por cenários da AWS](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/java)

## Programação síncrona e assíncrona
<a name="SyncAsyncProgramming"></a>

O AWS SDK for Java 2.x fornece clientes *síncronos* e *assíncronos* para Serviços da AWS, como o DynamoDB.

As classes `DynamoDbClient` e `DynamoDbEnhancedClient` fornecem métodos síncronos que bloqueiam a execução do seu thread até o cliente receber uma resposta do serviço. Esse cliente é a maneira mais simples de interagir com o DynamoDB se você não precisar de operações assíncronas.

As classes `DynamoDbAsyncClient` e `DynamoDbEnhancedAsyncClient` fornecem métodos assíncronos que são exibidos imediatamente e devolvem o controle ao thread de chamada sem aguardar uma resposta. O cliente sem bloqueio tem a vantagem de permitir alta simultaneidade em alguns segmentos, o que oferece tratamento eficiente de solicitações de E/S com recursos computacionais mínimos. Isso melhora o throughput e a capacidade de resposta.

O AWS SDK for Java 2.x usa o suporte nativo para E/S sem bloqueio. O AWS SDK para Java 1.x precisou simular E/S sem bloqueio.

Os métodos síncronos são exibidos antes que uma resposta esteja disponível, portanto você precisará de uma maneira de receber a resposta quando ela estiver pronta. Os métodos assíncronos no AWS SDK para Java exibem um objeto [https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/CompletableFuture.html](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/CompletableFuture.html) que contém os resultados da operação assíncrona no futuro. Ao chamar `get()` ou `join()` nesses objetos `CompletableFuture`, o código fica bloqueado até que o resultado esteja disponível. Se você fizer essas duas chamadas ao mesmo tempo em que faz a solicitação, o comportamento será semelhante a uma chamada síncrona simples.

Para obter mais informações sobre programação assíncrona, consulte [Use asynchronous programming](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/asynchronous.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

## Clientes HTTP
<a name="HttpClients"></a>

Para comportar cada cliente, existe um cliente HTTP que lida com a comunicação com os Serviços da AWS. É possível conectar clientes HTTP alternativos, escolhendo um que tenha as características mais adequadas à aplicação. Alguns são mais leves; alguns têm mais opções de configuração.

Alguns clientes HTTP comportam somente o uso síncrono, enquanto outros aceitam apenas o uso assíncrono. Para conferir um fluxograma que pode ajudar você a selecionar o cliente HTTP ideal para sua workload, consulte [HTTP client recommendations](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration.html#http-clients-recommend) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

A lista a seguir apresenta alguns dos possíveis clientes HTTP:

**Topics**
+ [Cliente HTTP baseado em Apache](#ApacheHttpClient)
+ [Cliente HTTP baseado em `URLConnection`](#URLConnHttpClient)
+ [Cliente HTTP baseado em Netty](#NettyHttpClient)
+ [Cliente HTTP baseado em AWS CRT](#AWSCRTHttpClient)

### Cliente HTTP baseado em Apache
<a name="ApacheHttpClient"></a>

A classe [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/apache/ApacheHttpClient.html) oferece suporte a clientes de serviço síncronos. É o cliente HTTP padrão para uso síncrono. Para obter informações sobre como configurar a classe `ApacheHttpClient`, consulte [Configure the Apache-based HTTP client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-apache.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

### Cliente HTTP baseado em `URLConnection`
<a name="URLConnHttpClient"></a>

A classe [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/urlconnection/UrlConnectionHttpClient.html) é outra opção para clientes síncronos. Ela é carregada mais rapidamente do que o cliente HTTP baseado em Apache, mas tem menos recursos. Para obter informações sobre como configurar a classe `UrlConnectionHttpClient`, consulte [Configure the URLConnection-based HTTP client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-url.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

### Cliente HTTP baseado em Netty
<a name="NettyHttpClient"></a>

A classe `NettyNioAsyncHttpClient` oferece suporte a clientes assíncronos. É a opção padrão para uso assíncrono. Para obter informações sobre como configurar a classe `NettyNioAsyncHttpClient`, consulte [Configure the Netty-based HTTP client](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-netty.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

### Cliente HTTP baseado em AWS CRT
<a name="AWSCRTHttpClient"></a>

As classes `AwsCrtHttpClient` e `AwsCrtAsyncHttpClient` mais recentes das bibliotecas AWS Common Runtime (CRT) são outra opção compatível com clientes síncronos e assíncronos. Em comparação com outros clientes HTTP, o AWS CRT oferece:
+ Menor tempo de inicialização do SDK
+ Menor espaço ocupado na memória
+ Tempo de latência reduzido
+ Gerenciamento de integridade da conexão
+ balanceamento de carga do DNS

Para obter informações sobre como configurar as classes `AwsCrtHttpClient` e `AwsCrtAsyncHttpClient`, consulte [Configure the AWS CRT-based HTTP clients](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-crt.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

O cliente HTTP baseado em AWS CRT não é o padrão porque isso romperia a compatibilidade com versões anteriores das aplicações existentes. No entanto, para o DynamoDB, recomendamos que você use o cliente HTTP baseado em AWS CRT para uso sincronizado e assíncrono.

Para conferir uma introdução sobre o cliente HTTP baseado em AWS CRT, consulte [Announcing availability of the AWS CRT HTTP Client in the AWS SDK for Java 2.x](https://aws.amazon.com/blogs/developer/announcing-availability-of-the-aws-crt-http-client-in-the-aws-sdk-for-java-2-x/) no *blog de ferramentas do desenvolvedor da AWS*.

## Configurar um cliente HTTP
<a name="ConfigHttpClient"></a>

Ao configurar um cliente, é possível fornecer várias opções de configuração, incluindo:
+ Definir tempos limite para diferentes aspectos das chamadas de API.
+ Habilitar keep-alive de TCP.
+ Controlar a política de novas tentativas ao encontrar erros.
+ Especificar atributos de execução que as instâncias do [interceptor de execução](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/interceptors.html) podem modificar. Os interceptores de execução podem escrever código que intercepte a execução de suas solicitações e respostas de API. Isso possibilita executar tarefas, como publicar métricas e modificar solicitações em andamento.
+ Adicionar ou manipular cabeçalhos HTTP.
+ Permitir o rastreamento das [métricas de performance do lado do cliente](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics.html). Usar esse recurso ajuda você a coletar métricas sobre os clientes de serviço em sua aplicação e analisar a saída no Amazon CloudWatch.
+ Especificar um serviço executor alternativo a ser usado para agendar tarefas, como novas tentativas assíncronas e tarefas de tempo limite.

Você controla a configuração fornecendo um objeto [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/config/ClientOverrideConfiguration.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/client/config/ClientOverrideConfiguration.html) para a classe `Builder` do cliente de serviço. Você verá isso em alguns exemplos de código nas seções a seguir.

A `ClientOverrideConfiguration` fornece opções de configuração padrão. Os diferentes clientes HTTP conectáveis também têm possibilidades de configuração específicas de implementação.

**Topics**
+ [Configuração de tempo limite](#TimeoutConfig)
+ [RetryMode](#RetryMode)
+ [DefaultsMode](#DefaultsMode)
+ [Configuração de keep-alive](#KeepAliveConfig)

### Configuração de tempo limite
<a name="TimeoutConfig"></a>

É possível ajustar a configuração do cliente para controlar vários tempos limite relacionados às chamadas de serviço. O DynamoDB fornece latências mais baixas em comparação com outros Serviços da AWS. Portanto, talvez você queira ajustar essas propriedades a fim de reduzir os valores de tempo limite para que possa antecipar-se à falha em caso de problema na rede.

É possível personalizar o comportamento relacionado à latência usando `ClientOverrideConfiguration` no cliente do DynamoDB ou alterando as opções de configuração detalhadas na implementação do cliente HTTP subjacente.

É possível configurar as seguintes propriedades impactantes usando `ClientOverrideConfiguration`:
+ `apiCallAttemptTimeout`: o tempo de espera até que uma única tentativa de solicitação HTTP seja concluída antes de desistir e atingir o tempo limite.
+ `apiCallTimeout`: o tempo que o cliente tem para executar completamente uma chamada de API. Isso inclui a execução do manipulador de solicitações, que consiste em todas as solicitações HTTP, incluindo novas tentativas.

O AWS SDK for Java 2.x fornece [valores padrão](https://github.com/aws/aws-sdk-java-v2/blob/a0c8a0af1fa572b16b5bd78f310594d642324156/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java#L134) para algumas opções de tempo limite, como tempo limite de conexão e tempo limite de soquete. O SDK não fornece valores padrão para tempo limite de chamadas de API nem tempos limite de chamadas de API individuais. Se esses tempos limite não estiverem definidos em `ClientOverrideConfiguration`, o SDK usará o valor do tempo limite do soquete para o tempo limite geral da chamada de API. O tempo limite do soquete tem um valor padrão de trinta minutos.

### RetryMode
<a name="RetryMode"></a>

Outra configuração relacionada à configuração de tempo limite que deve ser considerada é o objeto de configuração `RetryMode`. Esse objeto de configuração contém uma coleção de comportamentos de novas tentativas.

O SDK para Java 2.x é compatível com os seguintes modos de novas tentativas:
+ `legacy`: o modo de novas tentativas padrão, se você não o alterar explicitamente. Esse modo de novas tentativas é específico do SDK para Java. Ele é caracterizado por até três novas tentativas, ou mais para serviços, como o DynamoDB que tem até oito novas tentativas.
+ `standard`: é chamado de “standard” porque é mais consistente com outros SDKs da AWS. Esse modo espera por um período aleatório que varia de 0 ms a 1.000 ms pela primeira tentativa. Se outra tentativa for necessária, esse modo escolherá outro tempo aleatório entre 0 ms e 1.000 ms, e o multiplicará por dois. Se for necessária uma nova tentativa, ele fará a mesma escolha aleatória multiplicada por quatro e assim por diante. Cada espera é limitada a 20 segundos. Esse modo executa novas tentativas em mais condições de falha detectadas do que o modo `legacy`. Para o DynamoDB, ele executa até três tentativas no total, a menos que você substitua por [numRetries](#numRetries).
+ `adaptive`: baseia-se no modo `standard` e limita dinamicamente a taxa de solicitações da AWS para maximizar a taxa de êxito. Isso pode ocorrer em detrimento da latência da solicitação. Não recomendamos o modo de novas tentativas adaptável quando a latência previsível for importante.

É possível encontrar uma definição expandida desses modos de novas tentativas no tópico [Retry behavior](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html) no *Guia de referência de SDKs e ferramentas da AWS*.

#### Política de novas tentativas
<a name="RetryPolicies"></a>

Todas as configurações de `RetryMode` têm uma [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryPolicy.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryPolicy.html), que é criada com base em uma ou mais configurações de [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/conditions/RetryCondition.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/conditions/RetryCondition.html). [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/conditions/TokenBucketRetryCondition.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/conditions/TokenBucketRetryCondition.html) é especialmente importante para o comportamento de novas tentativas da implementação do cliente do SDK do DynamoDB. Essa condição limita o número de novas tentativas que o SDK faz usando um algoritmo de bucket de token. Dependendo do modo de novas tentativas selecionado, as exceções de controle de utilização podem ou não subtrair tokens do `TokenBucket`.

Quando um cliente encontra um erro que pode ser repetido, como uma exceção de controle de utilização ou um erro temporário do servidor, o SDK repete automaticamente a solicitação. É possível controlar quantas vezes e com que rapidez essas novas tentativas acontecem.

Ao configurar um cliente, é possível fornecer uma `RetryPolicy` compatível com os seguintes parâmetros:
+ `numRetries`: o número máximo de novas tentativas que devem ser aplicadas antes que uma solicitação seja considerada com falha. O valor padrão é 8, independentemente do modo de novas tentativas usado.
**Atenção**  
Certifique-se de alterar esse valor padrão após a devida consideração.
+ `backoffStrategy`: a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/backoff/BackoffStrategy.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/backoff/BackoffStrategy.html) a ser aplicada às novas tentativas, em que [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/backoff/FullJitterBackoffStrategy.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/backoff/FullJitterBackoffStrategy.html) é a estratégia padrão. Essa estratégia realiza um atraso exponencial entre novas tentativas com base no número ou nas novas tentativas atuais, um atraso base e um tempo máximo de recuo. Depois, adiciona instabilidade para fornecer um pouco de aleatoriedade. O atraso básico usado no atraso exponencial é de 25 ms, independentemente do modo de novas tentativas.
+ `retryCondition`: a [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/conditions/RetryCondition.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/conditions/RetryCondition.html) determina se uma solicitação deve ou não ser repetida. Por padrão, ela tenta novamente um conjunto específico de códigos de status HTTP e exceções que acredita serem passíveis de nova tentativa. Para a maioria das situações, a configuração padrão deve ser suficiente.

O código a seguir fornece uma política de novas tentativas alternativa. Ele especifica um total de cinco novas tentativas (seis solicitações no total). A primeira nova tentativa deve ocorrer após um atraso de aproximadamente 100 ms, com cada nova tentativa adicional dobrando esse tempo exponencialmente, até, no máximo, um atraso de 1 segundo.

```
DynamoDbClient client = DynamoDbClient.builder()
    .overrideConfiguration(ClientOverrideConfiguration.builder()
        .retryPolicy(RetryPolicy.builder()
            .backoffStrategy(FullJitterBackoffStrategy.builder()
                .baseDelay(Duration.ofMillis(100))
                .maxBackoffTime(Duration.ofSeconds(1))
                .build())
            .numRetries(5)
            .build())
        .build())
    .build();
```

### DefaultsMode
<a name="DefaultsMode"></a>

As propriedades de tempo limite que `ClientOverrideConfiguration` e `RetryMode` não gerenciam são normalmente configuradas implicitamente especificando um `DefaultsMode`.

O AWS SDK for Java 2.x (versão 2.17.102 ou posterior) introduziu suporte a `DefaultsMode`. Esse recurso oferece um conjunto de valores padrão para configurações comuns, como configurações de comunicação HTTP, comportamento de novas tentativas, configurações de endpoint regional do serviço e, potencialmente, qualquer configuração relacionada ao SDK. Os clientes que usam esse recurso podem receber novos padrões de configuração personalizados para cenários de uso comuns.

Os modos padrão são padronizados em todos os SDKs da AWS. O SDK para Java 2.x é compatível com os seguintes modos padrão:
+ `legacy`: fornece configurações padrão que variam de acordo com o SDK da AWS e que existiam antes do estabelecimento de `DefaultsMode`.
+ `standard`: fornece configurações padrão não otimizadas para a maioria dos cenários.
+ `in-region`: baseia-se no modo padrão e inclui configurações personalizadas para aplicações que chamam Serviços da AWS de dentro da mesma Região da AWS.
+ `cross-region`: baseia-se no modo padrão e inclui configurações com altos tempos limite para aplicações que chamam Serviços da AWS em uma região diferente.
+ `mobile`: baseia-se no modo padrão e inclui configurações com tempo limite alto, personalizadas para aplicações para dispositivos móveis com latências mais altas.
+ `auto`: baseia-se no modo padrão e inclui atributos experimentais. O SDK tenta descobrir o ambiente de runtime para determinar automaticamente as configurações apropriadas. A detecção automática é baseada em heurísticas e não fornece 100% de precisão. Se o ambiente de runtime não puder ser determinado, o modo padrão será usado. A detecção automática pode consultar [metadados da instância e dados do usuário](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html), o que pode introduzir latência. Se a latência de inicialização for fundamental para seu aplicativo, recomendamos escolher um `DefaultsMode` explícito.

É possível configurar o modo padrão das seguintes maneiras:
+ Diretamente em um cliente por meio de `AwsClientBuilder.Builder#defaultsMode(DefaultsMode)`.
+ Em um perfil de configuração por meio da propriedade do arquivo de perfil `defaults_mode`.
+ Globalmente por meio da propriedade do sistema `aws.defaultsMode`.
+ Globalmente por meio da variável de ambiente `AWS_DEFAULTS_MODE`.

**nota**  
Para qualquer modo que não seja `legacy`, os valores padrão fornecidos podem mudar à medida que as práticas recomendadas evoluem. Portanto, se estiver usando um modo diferente de `legacy`, recomendamos que você realize testes ao atualizar o SDK.

A seção [Smart configuration defaults](https://docs.aws.amazon.com/sdkref/latest/guide/feature-smart-config-defaults.html) no *Guia de referência de SDKs e ferramentas da AWS* fornece uma lista de propriedades de configuração e seus valores padrão nos diferentes modos padrão.

Escolha o valor de modo padrão com base nas características da aplicação e no AWS service (Serviço da AWS) com o qual a aplicação interage.

Esses valores são configurados com uma ampla seleção de Serviços da AWS em mente. Para uma implantação típica do DynamoDB em que a aplicação e as tabelas do DynamoDB são implantadas na mesma região, o modo `in-region` padrão é mais relevante entre os modos padrão `standard`.

**Example Configuração do cliente do SDK do DynamoDB ajustada para chamadas de baixa latência**  
O exemplo a seguir ajusta os tempos limite para valores mais baixos para uma chamada esperada do DynamoDB de baixa latência.  

```
DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.builder()
    .defaultsMode(DefaultsMode.IN_REGION)
    .httpClientBuilder(AwsCrtAsyncHttpClient.builder())
    .overrideConfiguration(ClientOverrideConfiguration.builder()
        .apiCallTimeout(Duration.ofSeconds(3))
        .apiCallAttemptTimeout(Duration.ofMillis(500))
        .build())
    .build();
```
A implementação do cliente HTTP individual pode fornecer a você um controle ainda mais granular sobre o tempo limite e o comportamento de uso da conexão. Por exemplo, para o cliente baseado em AWS CRT, é possível habilitar `ConnectionHealthConfiguration`, que permite que o cliente monitore ativamente a integridade das conexões usadas. Para obter mais informações, consulte [Advanced configuration of AWS CRT-based HTTP clients](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-crt.html#configuring-the-crt-based-http-client) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

### Configuração de keep-alive
<a name="KeepAliveConfig"></a>

Habilitar o keep-alive pode reduzir as latências ao reutilizar conexões. Há dois tipos diferentes de keep-alive: HTTP Keep-Alive e TCP Keep-Alive.
+ O HTTP Keep-Alive tenta manter a conexão HTTPS entre o cliente e o servidor para que solicitações posteriores possam reutilizar essa conexão. Isso ignora a pesada autenticação HTTPS em solicitações posteriores. O HTTP Keep-Alive está habilitado por padrão em todos os clientes.
+ O keep-alive de TCP solicita que o sistema operacional subjacente envie pequenos pacotes pela conexão do soquete a fim de fornecer garantia extra de que o soquete seja mantido ativo e para detectar imediatamente qualquer queda. Isso garante que não haja perda de tempo em uma solicitação posterior com a tentativa de usar um soquete descartado. Por padrão, o keep-alive de TCP está desabilitado em todos os clientes. Os exemplos de código a seguir mostram como habilitar essa opção em cada cliente HTTP. Quando habilitado para todos os clientes HTTP não baseados em CRT, o mecanismo real de keep-alive depende do sistema operacional. Portanto, é necessário configurar valores adicionais de TCP Keep-Alive, como tempo limite e número de pacotes, por meio do sistema operacional. É possível fazer isso usando `sysctl` no Linux ou macOS, ou usando valores de registro no Windows.

**Example para habilitar o TCP Keep-Alive em um cliente HTTP baseado em Apache**  

```
DynamoDbClient client = DynamoDbClient.builder()
    .httpClientBuilder(ApacheHttpClient.builder().tcpKeepAlive(true))
    .build();
```

**Cliente HTTP baseado em `URLConnection`**  
Nenhum cliente síncrono que usa o cliente HTTP baseado em `URLConnection` [https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html](https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html) tem um [mecanismo](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html) para habilitar o keep-alive.

**Example para habilitar o TCP Keep-Alive em um cliente HTTP baseado em Apache**  

```
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder()
    .httpClientBuilder(NettyNioAsyncHttpClient.builder().tcpKeepAlive(true))
    .build();
```

**Example para habilitar o TCP Keep-Alive em um cliente HTTP baseado em AWS CRT**  
Com o cliente HTTP baseado em AWS CRT, é possível habilitar o TCP Keep-Alive e controlar a duração.  

```
DynamoDbClient client = DynamoDbClient.builder()
    .httpClientBuilder(AwsCrtHttpClient.builder()
    .tcpKeepAliveConfiguration(TcpKeepAliveConfiguration.builder()
        .keepAliveInterval(Duration.ofSeconds(50))
        .keepAliveTimeout(Duration.ofSeconds(5))
        .build()))
    .build();
```
Ao usar o cliente assíncrono do DynamoDB, é possível habilitar o TCP Keep-Alive conforme mostrado no código a seguir.  

```
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder()
    .httpClientBuilder(AwsCrtAsyncHttpClient.builder()
    .tcpKeepAliveConfiguration(TcpKeepAliveConfiguration.builder()
        .keepAliveInterval(Duration.ofSeconds(50))
        .keepAliveTimeout(Duration.ofSeconds(5))
        .build()))
    .build();
```

## Tratamento de erros
<a name="JavaErrorHandling"></a>

No que se refere ao tratamento de exceções, o AWS SDK for Java 2.x usa exceções de tempo de execução (não conferidas).

A exceção básica, abrangendo todas as exceções do SDK, é [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/exception/SdkServiceException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/exception/SdkServiceException.html), que se estende da `RuntimeException` não conferida do Java. Se você captar isso, captará todas as exceções geradas pelo SDK.

`SdkServiceException` tem uma subclasse chamada [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/awscore/exception/AwsServiceException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/awscore/exception/AwsServiceException.html). Essa subclasse indica qualquer problema na comunicação com o AWS service (Serviço da AWS). Ela tem uma subclasse chamada [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html), que indica um problema na comunicação com o DynamoDB. Se você captar isso, captará todas as exceções relacionadas ao DynamoDB, mas nenhuma outra exceção do SDK.

Há [tipos de exceção](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/DynamoDbException.html) mais específicos em `DynamoDbException`. Alguns desses tipos de exceção se aplicam às operações do ambiente de gerenciamento, como [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TableAlreadyExistsException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/TableAlreadyExistsException.html). Outros se aplicam às operações do plano de dados. Veja a seguir um exemplo de exceção comum do plano de dados:
+ [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ConditionalCheckFailedException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ConditionalCheckFailedException.html): você especificou uma condição na solicitação que foi avaliada como falsa. Por exemplo, você pode ter tentado realizar uma atualização condicional em um item, mas o valor real do atributo não correspondeu ao valor esperado na condição. Uma solicitação que falhe dessa maneira não será repetida.

Outras situações não têm uma exceção específica definida. Por exemplo, quando suas solicitações têm controle de utilização, a `ProvisionedThroughputExceededException` específica pode ser gerada, enquanto, em outros casos, `DynamoDbException`mais genérica é lançada. Nos dois casos, é possível determinar se a exceção foi causada pelo controle de utilização, conferindo se `isThrottlingException()` retorna `true`.

Dependendo das necessidades da aplicação, é possível capturar todas as instâncias `AwsServiceException` ou `DynamoDbException`. No entanto, muitas vezes você precisa de um comportamento diferente em outras situações. A lógica para lidar com uma falha na verificação de condições é diferente quando se trata de lidar com o controle de utilização. Defina com quais caminhos excepcionais você deseja lidar e não se esqueça de testar os caminhos alternativos. Isso ajuda a garantir que você seja capaz de lidar com todos os cenários relevantes.

Para obter uma lista de erros comuns que você pode encontrar, consulte [Tratamento de erros com o DynamoDB](Programming.Errors.md). Consulte também [Common Errors](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/CommonErrors.html) na *Referência de API do Amazon DynamoDB*. A Referência de API também apresenta os erros exatos possíveis para cada operação de API, como a operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html). Para obter informações sobre como lidar com exceções, consulte [Exception handling for the AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/handling-exceptions.html) no *Guia do desenvolvedor do AWS SDK for Java 2.x*.

## ID da solicitação da AWS
<a name="JavaRequestID"></a>

Cada solicitação inclui um ID de solicitação cuja extração pode ser útil se você estiver trabalhando com AWS Support para diagnosticar um problema. Cada exceção derivada de `SdkServiceException` tem um método [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/exception/SdkServiceException.html#requestId()](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/exception/SdkServiceException.html#requestId()) disponível para recuperar o ID da solicitação.

## Registro em log
<a name="JavaLogging"></a>

Usar o registro em log fornecido pelo SDK pode ser útil tanto para capturar mensagens importantes das bibliotecas do cliente quanto para fins de depuração mais detalhada. Os loggers são hierárquicos e o SDK usa `software.amazon.awssdk` como logger raiz. Você pode configurar o nível com um dos seguintes: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ALL` ou `OFF`. O nível configurado é aplicado a esse logger e à hierarquia de loggers.

Para o registro em log, o AWS SDK for Java 2.x usa o Simple Logging Façade for Java (SLF4J). Isso atua como uma camada de abstração em torno de outros loggers, que pode ser usada para conectar o logger de sua preferência. Para ter instruções sobre como conectar loggers, consulte o [Manual do usuário do SLF4J](https://www.slf4j.org/manual.html).

Cada logger tem um comportamento específico. Por padrão, o logger Log4j 2.x cria um `ConsoleAppender`, que anexa eventos de log a `System.out` e assume o nível de log `ERROR` como padrão.

O logger SimpleLogger incluído no SLF4J, por padrão, emite por padrão `System.err` e utiliza como padrão o nível de log `INFO`.

Recomendamos definir o nível como `WARN` para `software.amazon.awssdk` para que todas as implantações em produção capturem todas as mensagens importantes das bibliotecas de cliente do SDK e limitem a quantidade de saída.

Se o SLF4J não conseguir encontrar um logger compatível no caminho da classe (sem vinculação ao SLF4J), ele assumirá como padrão uma [implementação sem operação](https://www.slf4j.org/codes.html#noProviders). Essa implementação ocasiona o registro em log de mensagens em `System.err` explicando que o SLF4J não conseguiu encontrar uma implementação de logger no caminho de classe. Para evitar essa situação, é necessário adicionar uma implementação de logger. Para fazer isso, é possível incluir uma dependência no Apache Maven `pom.xml` em artefatos, como `org.slf4j.slf4j-simple` ou `org.apache.logging.log4j.log4j-slf4j2-imp`.

Para obter informações sobre como configurar o registro em log no SDK, incluindo a adição de dependências de registro em log à configuração da aplicação, consulte [Logging with the SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/logging-slf4j.html) no *Guia do desenvolvedor do AWS SDK para Java*.

A configuração a seguir no arquivo `Log4j2.xml` mostra como ajustar o comportamento de registro em log se você usar o logger Apache Log4j 2. Essa configuração define o nível do logger raiz como `WARN`. Todos os loggers na hierarquia herdam esse nível de registro, incluindo o logger `software.amazon.awssdk`.

Por padrão, a saída é enviada para `System.out`. No exemplo a seguir, ainda substituímos o anexador Log4j de saída padrão para aplicar um Log4j personalizado `PatternLayout`.

**Exemplo de arquivo de configuração do `Log4j2.xml`**  
A configuração a seguir registra mensagens em log nos níveis `ERROR` e `WARN` no console para todas as hierarquias de logger.

```
<Configuration status="WARN">
  <Appenders>
    <Console name="ConsoleAppender" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
    </Console>
  </Appenders>

  <Loggers>
    <Root level="WARN">
      <AppenderRef ref="ConsoleAppender"/>
    </Root>
  </Loggers>
</Configuration>
```

### Registro em log de ID de solicitação da AWS
<a name="JavaReqIDLogging"></a>

Quando algo dá errado, você pode encontrar os IDs de solicitação nas exceções. No entanto, se você quiser os IDs das solicitações que não estão gerando exceções, poderá usar o registro em log.

O logger `software.amazon.awssdk.request` exibe os IDs de solicitação no nível `DEBUG`. O exemplo a seguir estende o [configuration example](#Log4j2ConfigEg) anterior para manter o nível do logger raiz em `ERROR`, o `software.amazon.awssdk` em nível `WARN` e o `software.amazon.awssdk.request` em nível `DEBUG`. A definição desses níveis ajuda a capturar os IDs de solicitação e outros detalhes relacionados à solicitação, como o endpoint e o código de status.

```
<Configuration status="WARN">
  <Appenders>
    <Console name="ConsoleAppender" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c:%L - %m%n" />
    </Console>
  </Appenders>

  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="ConsoleAppender"/>
    </Root>
    <Logger name="software.amazon.awssdk" level="WARN" />
    <Logger name="software.amazon.awssdk.request" level="DEBUG" />
  </Loggers>
</Configuration>
```

Aqui está um exemplo da saída do log:

```
2022-09-23 16:02:08 [main] DEBUG software.amazon.awssdk.request:85 - Sending Request: DefaultSdkHttpFullRequest(httpMethod=POST, protocol=https, host=dynamodb.us-east-1.amazonaws.com, encodedPath=/, headers=[amz-sdk-invocation-id, Content-Length, Content-Type, User-Agent, X-Amz-Target], queryParameters=[])
 2022-09-23 16:02:08 [main] DEBUG software.amazon.awssdk.request:85 - Received successful response: 200, Request ID: QS9DUMME2NHEDH8TGT9N5V53OJVV4KQNSO5AEMVJF66Q9ASUAAJG, Extended Request ID: not available
```

## Paginação
<a name="JavaPagination"></a>

Algumas solicitações, como [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) e [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html), limitam o tamanho dos dados retornadas em uma única solicitação e exigem que você faça solicitações repetidas para extrair as páginas subsequentes.

É possível controlar o número máximo de itens a serem lidos em cada página com o parâmetro `Limit`. Por exemplo, é possível usar o parâmetro `Limit` para recuperar somente os últimos dez itens. Esse limite especifica quantos itens devem ser lidos da tabela antes da aplicação de qualquer filtragem. Se você quiser exatamente dez itens após a filtragem, não há como especificar isso. Só é possível controlar a contagem pré-filtrada e verificar no lado do cliente quando tiver realmente recuperado dez itens. Independentemente do limite, as respostas sempre têm um tamanho máximo de 1 MB.

Uma `LastEvaluatedKey` pode ser incluída na resposta de API. Isso indica que a resposta terminou porque atingiu um limite de contagem ou um limite de tamanho. Essa chave é a última avaliada para essa resposta. Interagindo diretamente com a API, é possível recuperar essa `LastEvaluatedKey` e transmiti-la para uma chamada de acompanhamento como `ExclusiveStartKey` para ler a próxima parte desse ponto de partida. Se não for retornada nenhuma `LastEvaluatedKey`, significa que não há mais itens que correspondam à chamada de API `Query` ou `Scan`.

O exemplo a seguir usa a interface de nível inferior para limitar os itens a cem com base no parâmetro `keyConditionExpression`.

```
QueryRequest.Builder queryRequestBuilder = QueryRequest.builder()
        .expressionAttributeValues(Map.of(
                ":pk_val", AttributeValue.fromS("123"),
                ":sk_val", AttributeValue.fromN("1000")))
        .keyConditionExpression("pk = :pk_val AND sk > :sk_val")
        .limit(100)
        .tableName(TABLE_NAME);

while (true) {
    QueryResponse queryResponse = DYNAMODB_CLIENT.query(queryRequestBuilder.build());

    queryResponse.items().forEach(item -> {
        LOGGER.info("item PK: [" + item.get("pk") + "] and SK: [" + item.get("sk") + "]");
    });

    if (!queryResponse.hasLastEvaluatedKey()) {
        break;
    }
    queryRequestBuilder.exclusiveStartKey(queryResponse.lastEvaluatedKey());
}
```

O AWS SDK for Java 2.x pode simplificar essa interação com o DynamoDB, fornecendo métodos de paginação automática que fazem várias chamadas de serviço para obter as próximas páginas de resultados automaticamente. Isso simplifica o código, mas elimina uma parte do controle sobre o uso de recursos que você manteria lendo as páginas manualmente.

Usando os métodos `Iterable` disponíveis no cliente do DynamoDB, como [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html#queryPaginator(software.amazon.awssdk.services.dynamodb.model.QueryRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html#queryPaginator(software.amazon.awssdk.services.dynamodb.model.QueryRequest)) e [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html#scanPaginator(software.amazon.awssdk.services.dynamodb.model.ScanRequest)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/DynamoDbClient.html#scanPaginator(software.amazon.awssdk.services.dynamodb.model.ScanRequest)), o SDK cuida da paginação. O tipo de retorno desses métodos é um iterável personalizado que você pode usar para percorrer todas as páginas. O SDK lida internamente com as chamadas de serviço para você. Usando a API do Java Stream, é possível lidar com o resultado de `QueryPaginator`, conforme mostrado no exemplo a seguir.

```
QueryPublisher queryPublisher =
    DYNAMODB_CLIENT.queryPaginator(QueryRequest.builder()
        .expressionAttributeValues(Map.of(
            ":pk_val", AttributeValue.fromS("123"),
            ":sk_val", AttributeValue.fromN("1000")))
        .keyConditionExpression("pk = :pk_val AND sk > :sk_val")
        .limit(100)
        .tableName("YourTableName")
        .build());

queryPublisher.items().subscribe(item ->
    System.out.println(item.get("itemData"))).join();
```

## Anotações de classes de dados
<a name="JavaDataClassAnnotation"></a>

O SDK para Java fornece várias anotações que você pode colocar nos atributos da sua classe de dados. Essas anotações influenciam a forma como o SDK interage com os atributos. Ao adicionar uma anotação, é possível fazer com que um atributo se comporte como um contador atômico implícito, mantenha um valor de carimbo de data e hora gerado automaticamente ou rastreie o número da versão de um item. Para ter mais informações, consulte [Data class annotations](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html).

# Tratamento de erros com o DynamoDB
<a name="Programming.Errors"></a>

 Esta seção descreve erros de runtime e como lidar com eles. Ela também descreve códigos e mensagens de erro que são específicos para o Amazon DynamoDB. Para obter uma lista de erros comuns que se aplicam a todos os serviços da AWS, consulte [Gerenciamento de acesso](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/CommonErrors.html).

**Topics**
+ [Componentes de erros](#Programming.Errors.Components)
+ [Erros transacionais](#Programming.Errors.TransactionalErrors)
+ [Mensagens e códigos de erro](#Programming.Errors.MessagesAndCodes)
+ [Tratamento de erros na aplicação](#Programming.Errors.Handling)
+ [Repetições de erro e recuo exponencial](#Programming.Errors.RetryAndBackoff)
+ [Operações em lote e tratamento de erros](#Programming.Errors.BatchOperations)

## Componentes de erros
<a name="Programming.Errors.Components"></a>

Quando seu programa envia uma solicitação, o DynamoDB tenta processá-la. Se a solicitação for bem-sucedida, o DynamoDB retornará um código de status HTTP de êxito (`200 OK`), juntamente com os resultados da operação solicitada.

Se a solicitação falhar, o DynamoDB retornará um erro. Cada erro tem três componentes: 
+ Um código de status HTTP (como `400`).
+ Um nome de exceção (como `ResourceNotFoundException`).
+ Uma mensagem de erro (como `Requested resource not found: Table: tablename not found`).

Os AWS SDKs cuidam da propagação de erros para sua aplicação para que você possa tomar as medidas apropriadas. Por exemplo, em um programa Java, você pode escrever a lógica `try-catch` para lidar com um `ResourceNotFoundException`.

Se você não estiver usando um AWS SDK, será necessário analisar o conteúdo da resposta de baixo nível do DynamoDB. Veja a seguir um exemplo dessa resposta.

```
HTTP/1.1 400 Bad Request
x-amzn-RequestId: LDM6CJP8RMQ1FHKSC1RBVJFPNVV4KQNSO5AEMF66Q9ASUAAJG
Content-Type: application/x-amz-json-1.0
Content-Length: 240
Date: Thu, 15 Mar 2012 23:56:23 GMT

{"__type":"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",
"message":"Requested resource not found: Table: tablename not found"}
```

## Erros transacionais
<a name="Programming.Errors.TransactionalErrors"></a>

Para obter informações sobre erros transacionais, consulte [Tratamento de conflitos em transações com o DynamoDB](transaction-apis.md#transaction-conflict-handling)

## Mensagens e códigos de erro
<a name="Programming.Errors.MessagesAndCodes"></a>

Veja a seguir uma lista de exceções retornadas pelo DynamoDB, agrupadas por código de status HTTP. Se *OK para tentar novamente?* for *Sim*, você poderá enviar a mesma solicitação novamente. Se *OK to retry? (OK tentar novamente?)* for *No (Não)*, você deverá corrigir o problema no lado do cliente antes de enviar uma nova solicitação.

### Código de status HTTP 400
<a name="Programming.Errors.MessagesAndCodes.http400"></a>

Um código de status HTTP `400` indica um problema com sua solicitação, como falha de autenticação, parâmetros necessários ausentes ou limite excedido do throughput provisionado de uma tabela. Será necessário corrigir o problema no aplicativo antes de enviar a solicitação novamente.

**AccessDeniedException **  
Mensagem: *Acesso negado.*  
The client did not correctly sign the request. Se estiver usando um AWS SDK, as solicitações serão assinadas para você automaticamente. Do contrário, acesse o [Processo de assinatura do Signature versão 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) na *Referência geral da AWS*.  
OK para tentar novamente? Não

**ConditionalCheckFailedException**  
Mensagem: *A solicitação condicional falhou. *  
Você especificou uma condição avaliada como false. Por exemplo, você pode ter tentado realizar uma atualização condicional em um item, mas o valor real do atributo não correspondeu ao valor esperado na condição.  
OK para tentar novamente? Não

**IncompleteSignatureException**  
Mensagem: *A assinatura da solicitação não atende aos padrões da AWS*.  
A assinatura da solicitação não incluía todos os componentes necessários. Se estiver usando um AWS SDK, as solicitações serão assinadas para você automaticamente. Do contrário, acesse o [Processo de assinatura do Signature versão 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) na *Referência geral da AWS*.  
OK para tentar novamente? Não

**ItemCollectionSizeLimitExceededException**  
Mensagem: *Tamanho da coleção excedido.*  
Para uma tabela com um índice secundário local, um grupo de itens com o mesmo valor de chave de partição excedeu o limite de tamanho máximo de 10 GB. Para obter mais informações sobre coleções de itens, consulte [Conjuntos de itens em índices secundários locais](LSI.md#LSI.ItemCollections).  
OK para tentar novamente? Sim

**LimitExceededException**  
Mensagem: *Muitas operações para um assinante específico.*  
Existem muitas operações simultâneas no plano de controle. O número cumulativo de tabelas e índices no estado `CREATING`, `DELETING` ou `UPDATING` não pode exceder 500.  
OK para tentar novamente? Sim

**MissingAuthenticationTokenException**  
Mensagem: *A solicitação deve conter um ID de chave de acesso válido (registrado) na AWS*.  
A solicitação não incluía o cabeçalho de autorização necessário ou estava mal formada. Consulte [API de baixo nível do DynamoDB](Programming.LowLevelAPI.md).  
OK para tentar novamente? Não

**ProvisionedThroughputExceededException**  
Mensagem: *You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (Você excedeu seu throughput provisionado máximo permitida para uma tabela ou para um ou mais índices secundários globais.) Para visualizar métricas de performance para throughput provisionado versus throughput consumido, abra o [console do Amazon CloudWatch](https://console.aws.amazon.com/cloudwatch/home)*.  
O erro inclui uma lista de campos `ThrottlingReason` que apresenta um contexto específico sobre o motivo do controle de utilização, seguindo o formato `ResourceType+OperationType+LimitType` (p. ex., `TableReadProvisionedThroughputExceeded`) e o ARN do recurso afetado. Isso ajuda a identificar qual recurso está sofrendo controle de utilização (tabela ou índice), qual tipo de operação acionou o controle (leitura ou gravação) e o limite específico que foi excedido (nesse caso, capacidade provisionada). Para ter mais informações sobre como diagnosticar e resolver problemas de controle de utilização, consulte [Diagnosticar o controle de utilização](throttling-diagnosing-workflow.md).  
Exemplo: Sua taxa de solicitação é muito alta. Os AWS SDKs para o DynamoDB realizam automaticamente novas tentativas de envio de uma mesma solicitação que recebe essa exceção. Sua solicitação em algum momento terá êxito, a menos que a fila de novas tentativas seja muito grande para concluir. Reduza a frequência de solicitações usando [Repetições de erro e recuo exponencial](#Programming.Errors.RetryAndBackoff).   
OK para tentar novamente? Sim

**ReplicatedWriteConflictException**  
Mensagem: *um ou mais itens desta solicitação estão sendo modificados por uma solicitação em outra região.*  
Exemplo: uma operação de gravação foi solicitada para um item em uma tabela global multirregional fortemente consistente (MRSC) que está sendo modificada atualmente por uma solicitação em outra região.   
OK para tentar novamente? Sim

**RequestLimitExceeded**  
Mensagem: *Throughput exceeds the current throughput limit for your account (o throughput excede o limite de throughput atual de sua conta). Para solicitar um aumento de limite, entre em contato com o AWS Support em [https://aws.amazon.com/support](https://aws.amazon.com/support)*.  
O erro inclui uma lista de campos `ThrottlingReason` que apresenta um contexto específico sobre o motivo do controle de utilização, seguindo o formato `ResourceType+OperationType+LimitType` (p. ex., `TableWriteAccountLimitExceeded` ou `IndexReadAccountLimitExceeded`) e o ARN do recurso afetado. Isso ajuda você a identificar qual recurso está sofrendo controle de utilização (tabela ou índice), qual tipo de operação acionou o controle (leitura ou gravação) e se você excedeu as cotas de serviço em nível de conta. Para ter mais informações sobre como diagnosticar e resolver problemas de controle de utilização, consulte [Diagnosticar o controle de utilização](throttling-diagnosing-workflow.md).   
Exemplo: a taxa de solicitações sob demanda excede o throughput permitido da conta e a tabela não pode ser escalada além disso.  
OK para tentar novamente? Sim

**ResourceInUseException**  
Mensagem: *O recurso que você está tentando alterar está em uso. *  
Exemplo: você tentou recriar uma tabela existente ou excluir uma tabela atualmente no estado `CREATING`.   
OK para tentar novamente? Não

**ResourceNotFoundException **  
Mensagem: *O recurso solicitado não foi encontrado.*  
Exemplo: a tabela que está sendo solicitada não existe ou está há pouco tempo no estado `CREATING`.  
OK para tentar novamente? Não

**ThrottlingException**  
Mensagem: *A taxa de solicitações excede o throughput permitido.*  
Essa exceção é retornada como uma resposta da AmazonServiceException com um código de status THROTTLING\$1EXCEPTION. Essa exceção poderá ser retornada se você executar operações de API de [plano de controle](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.API.html#HowItWorks.API.ControlPlane) muito rapidamente.  
Para as tabelas que usam o modo sob demanda, essa exceção poderá ser retornada para qualquer operação de API do [plano de dados](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.API.html#HowItWorks.API.DataPlane) se a sua taxa de solicitação for muito alta. Para saber mais sobre escalabilidade sob demanda, consulte [Throughput inicial e propriedades de escalabilidade](on-demand-capacity-mode.md#on-demand-capacity-mode-initial).   
O erro inclui uma lista de campos `ThrottlingReason` que apresenta um contexto específico sobre o motivo do controle de utilização, seguindo o formato `ResourceType+OperationType+LimitType` (p. ex., `TableReadKeyRangeThroughputExceeded` ou `IndexWriteMaxOnDemandThroughputExceeded`) e o ARN do recurso afetado. Essas informações ajudam a identificar qual recurso está sofrendo controle de utilização (tabela ou índice), qual tipo de operação acionou o controle (leitura ou gravação) e o limite específico que foi excedido (limites de partição ou throughput máximo sob demanda). Para ter mais informações sobre como diagnosticar e resolver problemas de controle de utilização, consulte [Diagnosticar o controle de utilização](throttling-diagnosing-workflow.md).  
OK para tentar novamente? Sim

**UnrecognizedClientException**  
Mensagem: *o ID da chave de acesso ou o token de segurança é inválido.*  
A assinatura da solicitação está incorreta. A causa mais provável é um ID de chave de acesso da AWS ou uma chave secreta inválidos.  
OK para tentar novamente? Sim

**ValidationException**  
Mensagem: varia dependendo do erro específico encontrado  
Esse erro pode ocorrer por vários motivos, como um parâmetro necessário ausente, um valor fora do intervalo ou tipos de dados incompatíveis. A mensagem de erro contém detalhes sobre a parte específica da solicitação que causou o erro.  
OK para tentar novamente? Não

### Código de status HTTP 5xx
<a name="Programming.Errors.MessagesAndCodes.http5xx"></a>

Um código de status HTTP `5xx` indica um problema que deve ser resolvido pela AWS. Pode ser um erro transitório e, nesse caso, é possível repetir a solicitação até que ela tenha êxito. Caso contrário, acesse o [AWS Service Health Dashboard](https://status.aws.amazon.com/) para ver se há problemas operacionais com o serviço.

Para obter mais informações, consulte [Como resolver erros de HTTP 5xx no Amazon DynamoDB?](https://aws.amazon.com/premiumsupport/knowledge-center/dynamodb-http-5xx-errors/)

**InternalServerError (HTTP 500)**  
O DynamoDB não pôde processar a solicitação.  
OK para tentar novamente? Sim  
Você pode encontrar erros de servidor internos enquanto trabalha com itens. Esses são esperados durante a vida útil de uma tabela. Todas as solicitações com falha podem ser repetidas imediatamente.  
Quando você recebe um código de status 500 em uma operação de gravação, a operação pode ter sido concluída com sucesso ou com erro. Se a operação de gravação for uma solicitação `TransactWriteItem`, a operação pode ser repetida. Se a operação de gravação for uma solicitação de gravação de um único item, como `PutItem`, `UpdateItem` ou `DeleteItem`, sua aplicação deve ler o estado do item antes de tentar novamente a operação e/ou usar [Exemplo de expressão de condição do DynamoDB na CLI](Expressions.ConditionExpressions.md) para garantir que o item permaneça em um estado correto após tentar novamente, independentemente de a operação anterior ter sido concluída com sucesso ou com erro. Se a idempotência for um requisito para a operação de gravação, use [`TransactWriteItem`](transaction-apis.md#transaction-apis-txwriteitems), que é compatível com solicitações idempotentes, especificando automaticamente um `ClientRequestToken` para eliminar ambiguidades em várias tentativas de executar a mesma ação.

**ServiceUnavailable (HTTP 503)**  
O DynamoDB está indisponível no momento. (Esse estado deve ser temporário.)  
OK para tentar novamente? Sim

## Tratamento de erros na aplicação
<a name="Programming.Errors.Handling"></a>

Para que seu aplicativo seja executado sem problemas, é necessário adicionar uma lógica para detectar erros e reagir a eles. As abordagens comuns incluem o uso de blocos `try-catch` ou de uma instrução `if-then`.

Os AWS SDKs realizam por conta própria novas tentativas e verificações de erros. Se você se deparar com um erro enquanto usa um dos AWS SDKs, o código de erro e sua descrição poderão ajudar a solucioná-lo.

Você também deve ver um `Request ID` na resposta. O `Request ID` pode ser útil se você precisa trabalhar com o AWS Support para diagnosticar um problema.

## Repetições de erro e recuo exponencial
<a name="Programming.Errors.RetryAndBackoff"></a>

Vários componentes em uma rede, como servidores DNS, switches, load balancers e outros, podem gerar erros em qualquer momento do ciclo de vida de uma determinada solicitação. A técnica usual para lidar com essas respostas de erro em um ambiente de rede é implementar novas tentativas no aplicativo cliente. Essa técnica aumenta a confiabilidade da aplicação.

Cada AWS SDK implementa a lógica de novas tentativas automaticamente. Você pode modificar os parâmetros de novas tentativas de acordo com as suas necessidades. Por exemplo, considere um aplicativo Java que exija uma estratégia rápida contra falhas, sem permitir novas tentativas em caso de erro. Com o AWS SDK para Java, você poderia usar a classe `ClientConfiguration` e fornecer um valor `maxErrorRetry` de `0` para desativar as novas tentativas. Para obter mais informações, consulte a documentação do AWS SDK para sua linguagem de programação.

Se não estiver usando um AWS SDK, você deverá tentar novamente as solicitações originais que recebem erros do servidor (5xx). No entanto, erros de cliente (4xx, diferente de `ThrottlingException` ou `ProvisionedThroughputExceededException`) indicam que você precisa revisar a solicitação para corrigir o problema antes de tentar novamente. Para obter recomendações detalhadas para abordar cenários específicos de controle de utilização, consulte a seção [Solução de problemas de controle de utilização do DynamoDB](TroubleshootingThrottling.md).

Além de novas tentativas simples, cada AWS SDK implementa um algoritmo de recuo exponencial para um melhor controle de fluxo. O conceito por detrás do recuo exponencial é usar esperas progressivamente mais longas entre as novas tentativas para respostas de erro consecutivas. Por exemplo, até 50 milissegundos antes da primeira nova tentativa, até 100 milissegundos antes da segundo, até 200 milissegundos antes da terceira e assim por diante. No entanto, depois de um minuto, se a solicitação não tiver sido bem-sucedida, talvez o problema esteja relacionado ao tamanho da solicitação que exceda o throughput provisionado e não à taxa de solicitação. Defina um tempo de interrupção de cerca de um minuto para o número máximo de novas tentativas. Se a solicitação não for bem-sucedida, investigue suas opções de throughput provisionado. 

**nota**  
Os AWS SDKs implementam uma lógica de novas tentativas automáticas e de recuo exponencial.

A maioria dos algoritmos de recuo exponencial usam variação (atraso randomizado) para evitar colisões sucessivas. Como você não está tentando evitar essas colisões nesses casos, não precisa usar esse número aleatório. No entanto, se você usar clientes simultâneos, a variação pode ajudar suas solicitações a serem bem-sucedidas mais depressa. Para obter mais informações, consulte a postagem no blog sobre [Recuo exponencial e variação](http://www.awsarchitectureblog.com/2015/03/backoff.html).

## Operações em lote e tratamento de erros
<a name="Programming.Errors.BatchOperations"></a>

A API de baixo nível do DynamoDB oferece suporte a operações em lote para leituras e gravações. `BatchGetItem` lê os itens de uma ou mais tabelas, e `BatchWriteItem` insere ou exclui itens de uma ou mais tabelas. Essas operações em lote são implementadas como wrappers em torno de outras operações do DynamoDB que não são feitas em lote. Em outras palavras, `BatchGetItem` invoca `GetItem` uma vez para cada item do lote. Da mesma forma, `BatchWriteItem` invoca `DeleteItem` ou `PutItem`, conforme apropriado, para cada item do lote.

Uma operação em lote pode tolerar a falha de solicitações individuais no lote. Por exemplo, considere uma solicitação `BatchGetItem` para ler cinco itens. Mesmo se algumas das solicitações `GetItem` subjacentes falharem, isso não faz com que toda a operação `BatchGetItem` falhe. Entretanto, se todas as cinco operações de leitura falharem, todo o `BatchGetItem` falhará.

As operações em lote retornam informações sobre solicitações individuais que apresentam falhas, para que você possa diagnosticar o problema e repetir a operação. Para `BatchGetItem`, as tabelas e chaves primárias em questão são retornadas no valor de `UnprocessedKeys` da resposta. Para `BatchWriteItem`, informações semelhantes são retornadas em `UnprocessedItems`. 

A causa mais provável de uma falha de leitura ou gravação é a *controle de utilização*. Para `BatchGetItem`, uma ou mais das tabelas na solicitação em lote não tem capacidade de leitura provisionada suficiente para dar suporte à operação. Para `BatchWriteItem`, uma ou mais das tabelas não tem capacidade de gravação provisionada suficiente.

Se o DynamoDB retornar itens não processados, você deverá repetir a operação em lote nesses itens. No entanto, *recomendamos que você use um algoritmo de recuo exponencial*. Se você repetir a operação em lote imediatamente, solicitações subjacentes de leitura ou gravação ainda poderão falhar devido ao controle de utilização nas tabelas individuais. Se você atrasar a operação em lote usando o recuo exponencial, as solicitações individuais no lote terão muito mais chances de sucesso.

**nota**  
Como alguns SDKs da AWS oferecem clientes de nível superior que lidam automaticamente com novas tentativas de itens não processados, você não precisa implementar essa lógica de repetição por conta própria. Por exemplo:  
**Java**: o [Cliente Aprimorado do DynamoDB](DynamoDBEnhanced.md) no AWS SDK para Java v2 e o [DynamoDBMapper](DynamoDBMapper.md) na v1 reexecutam automaticamente os itens não processados ao realizar operações em lote.
**Python**: o recurso de tabela `batch_writer` do Boto3 lida implicitamente com novas tentativas de itens não processados para operações de gravação em lote. Para obter mais informações, consulte [Usar o recurso de tabela batch\$1writer](programming-with-python.md#programming-with-python-batch-writer).
Se estiver usando um cliente de baixo nível ou um SDK que não oferece esse comportamento, você deverá implementar a lógica de novas tentativas por conta própria conforme descrito acima.

# Usar o DynamoDB com um AWS SDK
<a name="sdk-general-information-section"></a>

Os kits de desenvolvimento de software (SDKs) da AWS estão disponíveis para muitas linguagens de programação populares. Cada SDK fornece uma API, exemplos de código e documentação que permitem que os desenvolvedores criem facilmente aplicações em seu idioma de preferência.


| Documentação do SDK | Exemplos de código | 
| --- | --- | 
| [AWS SDK para C\$1\$1](https://docs.aws.amazon.com/sdk-for-cpp) | [AWS SDK para C\$1\$1 Exemplos de código](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp) | 
| [AWS CLI](https://docs.aws.amazon.com/cli) | [AWS CLI Exemplos de código da](https://docs.aws.amazon.com/code-library/latest/ug/cli_2_code_examples.html) | 
| [AWS SDK para Go](https://docs.aws.amazon.com/sdk-for-go) | [AWS SDK para Go Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/gov2) | 
| [AWS SDK para Java](https://docs.aws.amazon.com/sdk-for-java) | [AWS SDK para Java Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2) | 
| [AWS SDK para JavaScript](https://docs.aws.amazon.com/sdk-for-javascript) | [AWS SDK para JavaScript Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javascriptv3) | 
| [AWS SDK para Kotlin](https://docs.aws.amazon.com/sdk-for-kotlin) | [AWS SDK para Kotlin Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin) | 
| [AWS SDK para .NET](https://docs.aws.amazon.com/sdk-for-net) | [AWS SDK para .NET Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3) | 
| [AWS SDK para PHP](https://docs.aws.amazon.com/sdk-for-php) | [AWS SDK para PHP Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/php) | 
| [Ferramentas da AWS para PowerShell](https://docs.aws.amazon.com/powershell) | [Ferramentas da AWS para PowerShell Exemplos de código da](https://docs.aws.amazon.com/code-library/latest/ug/powershell_5_code_examples.html) | 
| [AWS SDK para Python (Boto3)](https://docs.aws.amazon.com/pythonsdk) | [AWS SDK para Python (Boto3) Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python) | 
| [AWS SDK para Ruby](https://docs.aws.amazon.com/sdk-for-ruby) | [AWS SDK para Ruby Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/ruby) | 
| [AWS SDK para Rust](https://docs.aws.amazon.com/sdk-for-rust) | [AWS SDK para Rust Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1) | 
| [AWS SDK para SAP ABAP](https://docs.aws.amazon.com/sdk-for-sapabap) | [AWS SDK para SAP ABAP Exemplos de código da](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/sap-abap) | 
| [AWS SDK para Swift](https://docs.aws.amazon.com/sdk-for-swift) | [AWS SDK para Swift Exemplos de código do](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/swift) | 

Para obter exemplos específicos do DynamoDB, consulte [Exemplos de código do DynamoDB usando AWS SDKs](service_code_examples.md).

**Exemplo de disponibilidade**  
Não consegue encontrar o que precisa? Solicite um exemplo de código usando o link **Fornecer feedback** na parte inferior desta página.