

# 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).