本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 程式設計 DynamoDB AWS SDK for Java 2.x
此程式設計指南為想要搭配 Java 使用 Amazon DynamoDB 的程式設計人員提供指導。本指南涵蓋不同的概念,包括抽象層、組態管理、錯誤處理、控制重試政策和管理保持連線。
主題
關於 AWS SDK for Java 2.x
您可以使用 官方從 Java 存取 DynamoDB 適用於 Java 的 AWS SDK。適用於 Java 的 SDK 有兩個版本:1.x 和 2.x。1.x 版本已於 2024 年 1 月 12 日宣布
如需有關維護和支援 AWS SDKs,請參閱《 AWS SDK 和工具參考指南》中的 SDK 和工具維護政策和 AWS SDKs 和工具版本支援矩陣。 AWS SDKs
AWS SDK for Java 2.x 是 1.x 程式碼基底的主要重寫。適用於 Java 2.x 的 SDK 支援現代 Java 功能,例如 Java 8 中引入的非封鎖 I/O。適用於 Java 2.x 的 SDK 也新增了對可插入 HTTP 用戶端實作的支援,以提供更多的網路連線彈性和組態選項。
適用於 Java 1.x 的 SDK 和適用於 Java 2.x 的 SDK 之間的明顯變更是使用新的套件名稱。Java 1.x SDK 使用 com.amazonaws 套件名稱,而 Java 2.x SDK 使用 software.amazon.awssdk。同樣地,Java 1.x SDK 的 Maven 成品使用 com.amazonaws groupId,而 Java 2.x SDK 成品則使用 software.amazon.awssdk groupId。
重要
支援 Java 版本
AWS SDK for Java 2.x 提供長期支援 (LTS) Java 版本
AWS SDK for Java 2.x入門
下列教學課程說明如何使用 Apache Maven
為了完成本教學,您需要執行以下各項:
步驟 1:設定本教學課程
在開始本教學課程之前,您需要以下項目:
-
存取 DynamoDB 的許可。
-
使用 設定單一登入存取的 Java AWS 服務 開發環境 AWS 存取入口網站。
若要設定本教學課程,請遵循 AWS SDK for Java 2.x 開發人員指南中設定概觀中的指示。設定具有單一登入存取設定的開發環境 (針對 Java SDK),並擁有作用中的 AWS 存取入口網站工作階段後,請繼續本教學課程的步驟 2。
步驟 2:建立專案
若要建立本教學課程的專案,請執行 Maven 命令,該命令會提示您輸入如何設定專案。輸入並確認所有輸入後,Maven 會建立 pom.xml 檔案和建立 stub Java 檔案來完成建置專案。
-
開啟終端機或命令提示視窗,然後導覽至您選擇的目錄,例如您的
Desktop或Home資料夾。 -
在終端輸入下列命令,然後按下 Enter 鍵。
mvn archetype:generate \ -DarchetypeGroupId=software.amazon.awssdk \ -DarchetypeArtifactId=archetype-app-quickstart \ -DarchetypeVersion=2.22.0 -
針對每個提示,輸入第二欄中列出的值。
提示詞 要輸入的值 Define value for property 'service':dynamodbDefine value for property 'httpClient':apache-clientDefine value for property 'nativeImage':falseDefine value for property 'credentialProvider'identity-centerDefine value for property 'groupId':org.exampleDefine value for property 'artifactId':getstartedDefine value for property 'version' 1.0-SNAPSHOT:<Enter>Define value for property 'package' org.example:<Enter> -
輸入最後一個值後,Maven 會列出您所做的選擇。若要確認,請輸入 Y。或者輸入 N,然後重新輸入您的選擇。
Maven 會根據您輸入的 artifactId 值建立名為 getstarted 的專案資料夾。在 getstarted 資料夾中,尋找名為 README.md 的檔案以供檢閱、pom.xml 檔案和 src 目錄。
Maven 會建置下列目錄樹狀目錄。
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
下列顯示 pom.xml 專案檔案的內容。
dependencyManagement 區段包含 AWS SDK for Java 2.x的相依性,而 dependencies 區段具有 DynamoDB 的相依性。指定這些相依性會強制 Maven 在 Java 類別路徑中包含相關的 .jar 檔案。根據預設, AWS 軟體開發套件不會包含所有 的所有類別 AWS 服務。對於 DynamoDB,如果您使用低階介面,則應具有對 dynamodb 成品的相依性。或者,如果您使用高階介面,則為 dynamodb-enhanced 成品。如果您未包含相關的相依性,則程式碼無法編譯。由於 maven.compiler.source 和 maven.compiler.target 屬性中的 1.8 值,專案使用 Java 1.8。
<?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>
步驟 3:撰寫程式碼
下列程式碼顯示 Maven 建立的 App 類別。main 方法是應用程式的進入點,它會建立 Handler 類別的執行個體,然後呼叫其 sendRequest 方法。
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"); } }
Maven 建立的 DependencyFactory 類別包含建置和傳回 DynamoDbClientdynamoDbClient 原廠方法。DynamoDbClient 執行個體使用 Apache 型 HTTP 用戶端的執行個體。這是因為您在 Maven 提示您使用哪個 HTTP 用戶端時指定了 apache-client。
下列程式碼顯示 DependencyFactory 類別。
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(); } }
Handler 類別包含您程式的主要邏輯。App 類別中建立了 Handler 的執行個體時,DependencyFactory 會提供 DynamoDbClient 服務用戶端。您的程式碼使用 DynamoDbClient 執行個體來呼叫 DynamoDB。
Maven 會產生具有 TODO 註解的下列 Handler 類別。教學課程中的下一個步驟會以程式碼取代 TODO 註解。
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. } }
若要填入邏輯,請使用下列程式碼取代 Handler 類別的整個內容。sendRequest 方法已填入,並新增必要的匯入。
下列程式碼使用 DynamoDbClientLogger 執行個體來記錄這些資料表的名稱。
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)); } } }
步驟 4:建置並執行應用程式
在您建立專案並包含完整的 Handler 類別之後,請建置並執行應用程式。
-
請確定您有一個作用中的 AWS IAM Identity Center 工作階段。若要確認,請執行 AWS Command Line Interface (AWS CLI) 命令
aws sts get-caller-identity並檢查回應。如果您沒有作用中的工作階段,請參閱使用 AWS CLI登入以取得指示。 -
開啟終端機或命令提示視窗,然後導覽至您的專案目錄
getstarted。 -
使用下列命令來建置專案:
mvn clean package -
若要部署應用程式,請執行下列命令:
mvn exec:java -Dexec.mainClass="org.example.App"
檢視檔案之後,請刪除物件,然後刪除儲存貯體。
成功
如果您的 Maven 專案能建置且執行時沒有錯誤,恭喜您!您已成功使用適用於 Java 的 SDK 2.x 建置了第一個 Java 應用程式。
清除
若要清除您在本教學課程中建立的資源,請刪除專案資料夾 getstarted。
檢閱 AWS SDK for Java 2.x 文件
AWS SDK for Java 2.x 開發人員指南涵蓋 SDK 在一切 AWS 服務中的所有層面。建議您檢閱下列主題:
-
從 1.x 版移轉至 2.x – 包含 1.x 和 2.x 之間差異的詳細說明。本主題也包含如何使用兩個主要版本的指示,以並排方式顯示。
-
適用於 Java 2.x SDK 的 DynamoDB 指南 – 說明如何執行基本的 DynamoDB 操作:建立資料表、操作項目和擷取項目。這些範例使用低階介面。Java 有數個介面,如下節所述:支援的介面。
提示
檢閱這些主題之後,請將 AWS SDK for Java 2.x API 參考
支援的介面
根據您想要的抽象程度, AWS SDK for Java 2.x 支援下列界面。
低階介面
低階介面提供對基礎服務 API 的 1 對 1 映射。每個 DynamoDB API 都可以透過此介面使用。這表示低階介面可以提供完整的功能,但通常使用起來更冗長且複雜。例如,您必須使用 .s() 函數來保留字串,並使用 .n() 函數來保留數字。下列 PutItem 範例使用低階介面插入項目。
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)"); } }
高階介面
中的高階界面 AWS SDK for Java 2.x 稱為 DynamoDB 增強型用戶端。此介面提供更道地的程式碼撰寫體驗。
增強型用戶端提供一種在用戶端資料類別和旨在存放該資料的 DynamoDB 資料表之間映射的方法。您要在自己的程式碼中定義資料表及其對應模型類別之間的關係。然後,您可以依賴 SDK 來管理資料類型處理。如需增強型用戶端的詳細資訊,請參閱《AWS SDK for Java 2.x 開發人員指南》中的 DynamoDB 增強型用戶端 API。
下列 PutItem 範例使用高階介面。在此範例中,名為 YourItem 的 DynamoDbBean 會建立 TableSchema,使其能夠直接使用為 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; } } }
適用於 Java 的 AWS SDK 1.x 有自己的高階界面,通常由其主要類別 參考。 DynamoDBMapper AWS SDK for Java 2.x 會以名為 的個別套件 (和 Maven 成品) 發佈software.amazon.awssdk.enhanced.dynamodb。Java 2.x SDK 通常由其主類別 DynamoDbEnhancedClient 參考。
使用不可變資料類別的高階介面
DynamoDB 增強型用戶端 API 的映射功能也適用於不可變的資料類別。不可變類別只有取得器,且需要 SDK 用來建立類別執行個體的建置器類別。Java 中的不可變性是一種常用的樣式,開發人員可用來建立沒有副作用的類別。這些類別在複雜多執行緒應用程式中的行為更可預測。不可變類別會使用 @DynamoDbImmutable 註釋,其採用建置器類別做為其輸入,而不是使用 High-level interface example 中所示的 @DynamoDbBean 註釋。
下列範例採用建置器類別 DynamoDbEnhancedClientImmutablePutItem 做為輸入來建立資料表結構描述。然後,此範例提供結構描述做為 PutItem API 呼叫的輸入。
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)"); } }
下列範例顯示不可變的資料類別。
@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); } } }
使用不可變資料類別和第三方樣板產生程式庫的高階介面
不可變的資料類別 (如上例所示) 需要一些樣板程式碼。例如,除了 Builder 類別之外,對資料類別的取得器和設定器邏輯。例如 Project Lombok
下列範例示範 Project Lombok 如何簡化使用 DynamoDB 增強型用戶端 API 所需的程式碼。
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)"); } }
下列範例顯示不可變資料類別的不可變資料物件。
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; }
YourImmutableLombokItem 類別使用 Project Lombok 和 AWS SDK 提供的下列註釋:
-
@Builder
– 為 Project Lombok 提供的資料類別產生複雜的建置器 API。 -
@DynamoDbImmutable
– 將 DynamoDbImmutable類別識別為 AWS 開發套件提供的 DynamoDB 可映射實體註釋。 -
@Value
– @Data的不可變變體。根據預設,所有欄位都是私有和最終欄位,不會產生設定器。Project Lombok 提供此註釋。
文件介面
AWS SDK for Java 2.x 文件界面不需要指定資料類型描述項。資料類型是由資料本身的語義隱含的。此文件界面類似於 文件界面 適用於 Java 的 AWS SDK 1.x,但具有重新設計的界面。
以下 Document interface example 顯示使用文件介面表示的 PutItem 呼叫。此範例也使用 EnhancedDocument。若要使用增強型文件 API 針對 DynamoDB 資料表執行命令,您必須先將資料表與文件資料表結構描述建立關聯,才能建立 DynamoDBTable 資源物件。文件資料表結構描述建置器需要主索引鍵和屬性轉換器提供者。
您可以使用 AttributeConverterProvider.defaultProvider() 來轉換預設類型的文件屬性。您可以使用自訂 AttributeConverterProvider 實作變更整體預設行為。您也可以變更單一屬性的轉換器。AWS SDK 和工具參考指南提供有關如何使用自訂轉換器的更多詳細資訊和範例。其主要用途是用於沒有預設轉換器的網域類別屬性。使用自訂轉換器,您可以向 SDK 提供寫入或讀取至 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)"); } }
若要將原生 Amazon DynamoDB 資料類型與 JSON 文件彼此轉換,您可以使用下列公用程式方法:
-
EnhancedDocument.fromJson(String json)– 從 JSON 字串建立新的 EnhancedDocument 實體。 -
EnhancedDocument.toJson()– 建立文件的 JSON 字串表示法,您可以在應用程式中使用,就像任何其他 JSON 物件一樣。
使用 Query 範例比較各介面
本節顯示使用各種介面表示的相同 Query 呼叫。若要微調這些查詢的結果,請注意下列事項:
-
DynamoDB 以一個特定的分割區索引鍵值為目標,因此您必須完全指定分割區索引鍵。
-
若要讓查詢目標僅購物車項目,排序索引鍵具有使用
begins_with的索引鍵條件表達式。 -
我們使用
limit()將查詢限制為最多傳回 100 個項目。 -
我們將
scanIndexForward設定為 false。結果會依 UTF-8 位元組的順序傳回,這通常表示會先傳回數量最低的購物車項目。透過將scanIndexForward設定為 false,我們把順序反轉,並先傳回數量最高的購物車項目。 -
我們會套用篩選條件,以移除不符合條件的任何結果。篩選的資料會耗用讀取容量,無論項目是否符合篩選條件。
範例 Query 使用低階介面
下列範例使用 keyConditionExpression 查詢名為 YourTableName 的資料表。這會將查詢限制為特定的分割區索引鍵值,以及以特定字首值開頭的排序索引鍵值。這些金鑰條件會限制從 DynamoDB 讀取的資料量。最後,查詢會對使用 filterExpression 從 DynamoDB 擷取的資料套用篩選條件。
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")); } }
範例 Query 使用文件介面
下列範例會使用文件介面查詢名為 YourTableName 的資料表。
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")); } }
範例 Query 使用高階介面
下列範例會使用 DynamoDB 增強型用戶端 API 查詢名為 YourTableName 的資料表。
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; } } }
使用不可變資料類別的高階介面
當您使用高階不可變資料類別執行 Query 時,程式碼會與高階介面範例相同,但實體類別 YourItem 或 YourImmutableItem 的建構除外。如需詳細資訊,請參閱 PutItem 範例。
使用不可變資料類別和第三方樣板產生程式庫的高階介面
當您使用高階不可變資料類別執行 Query 時,程式碼會與高階介面範例相同,但實體類別 YourItem 或 YourImmutableLombokItem 的建構除外。如需詳細資訊,請參閱 PutItem 範例。
其他程式碼範例
如需如何搭配適用於 Java 2.x 的 SDK 使用 DynamoDB 的其他範例,請參閱下列程式碼範例儲存庫:
同步和非同步程式設計
為 AWS SDK for Java 2.x 提供同步和非同步用戶端 AWS 服務,例如 DynamoDB。
DynamoDbClient 和 DynamoDbEnhancedClient 類別提供同步方法,這些方法會封鎖您的執行緒執行,直到用戶端收到服務的回應。如果您不需要非同步操作,此用戶端是與 DynamoDB 互動最直接的方式。
DynamoDbAsyncClient 和 DynamoDbEnhancedAsyncClient 類別提供非同步方法,這些方法會立即傳回,將控制權交還給呼叫端執行緒,無需等待回應。非封鎖用戶端具有優勢,可在幾個執行緒中用於獲得高並行,以最少的運算資源有效率地處理 I/O 請求。這可改善輸送量和回應能力。
AWS SDK for Java 2.x 使用原生支援進行非封鎖 I/O。 適用於 Java 的 AWS SDK 1.x 必須模擬非封鎖 I/O。
同步方法會在有可用回應時傳回結果,您需要一個方法在回應準備好時取得回應。中的非同步方法會 適用於 Java 的 AWS SDK 傳回CompletableFutureCompletableFuture 物件呼叫 get() 或 join() 時,您的程式碼會封鎖,直到結果可用為止。如果您在提出請求的同時呼叫這些函數,則行為類似於純同步呼叫。
如需非同步程式設計的詳細資訊,請參閱《AWS SDK for Java 2.x 開發人員指南》中的使用非同步程式設計。
HTTP 用戶端
為了支援每個用戶端,有一個 HTTP 用戶端來處理與 AWS 服務的通訊。您可以插入替代 HTTP 用戶端,選擇具有最符合您應用程式特性的用戶端。有些更輕量;有些則有更多組態選項。
有些 HTTP 用戶端僅支援同步使用,有些僅支援非同步使用。如需可協助您為工作負載選取最佳 HTTP 用戶端的流程圖,請參閱《AWS SDK for Java 2.x 開發人員指南》中的 HTTP 用戶端建議。
下列清單顯示一些可能的 HTTP 用戶端:
Apache 型 HTTP 用戶端
ApacheHttpClientApacheHttpClient 類別的資訊,請參閱《AWS SDK for Java 2.x 開發人員指南》中的設定 Apache 型 HTTP 用戶端。
URLConnection 型 HTTP 用戶端
UrlConnectionHttpClientUrlConnectionHttpClient 類別的資訊,請參閱《AWS SDK for Java 2.x 開發人員指南》中的設定 URLConnection 型 HTTP 用戶端。
Netty 型 HTTP 用戶端
NettyNioAsyncHttpClient 類別支援非同步用戶端。這是非同步使用的預設選擇。如需有關 NettyNioAsyncHttpClient 類別的資訊,請參閱《AWS SDK for Java 2.x 開發人員指南》中的設定 Netty 型 HTTP 用戶端。
AWS CRT 型 HTTP 用戶端
Common AWS Runtime (CRT) 程式庫中較新的 AwsCrtHttpClient 和 AwsCrtAsyncHttpClient類別是支援同步和非同步用戶端的更多選項。相較於其他 HTTP 用戶端, AWS CRT 提供:
-
更快速的 SDK 啟動時間
-
記憶體佔用空間較小
-
延遲時間縮短
-
連線運作狀態管理
-
DNS 負載平衡
如需設定 AwsCrtHttpClient和 AwsCrtAsyncHttpClient類別的資訊,請參閱《 AWS SDK for Java 2.x 開發人員指南》中的設定 AWS CRT 型 HTTP 用戶端。
AWS CRT 型 HTTP 用戶端不是預設值,因為這會破壞現有應用程式的回溯相容性。不過,對於 DynamoDB,我們建議您將 AWS CRT 型 HTTP 用戶端用於同步和非同步用途。
如需 AWS CRT 型 HTTP 用戶端的簡介,請參閱《 AWS 開發人員工具部落格》中的宣布 AWS CRT HTTP 用戶端的可用性 AWS SDK for Java 2.x
設定 HTTP 用戶端
設定用戶端時,您可以提供各種組態選項,包括:
您可以提供 ClientOverrideConfigurationBuilder 類別以控制組態。您會在下列各節的一些程式碼範例中看到此情況。
ClientOverrideConfiguration 提供標準組態選擇。不同的可插入 HTTP 用戶端也有實作特定的組態可能性。
逾時組態
您可以調整用戶端組態,以控制與服務呼叫相關的各種逾時。與其他 AWS 服務相比,DynamoDB 提供較低的延遲。因此,您可能想要將這些屬性調整為較低的逾時值,以便在發生聯網問題時快速檢錯。
您可以在 DynamoDB 用戶端上使用 ClientOverrideConfiguration,或針對基礎 HTTP 用戶端實作變更詳細的組態選項,以自訂延遲相關行為。
您可以使用 ClientOverrideConfiguration 來設定下列具影響力的屬性:
-
apiCallAttemptTimeout– 在放棄和逾時之前,等待 HTTP 請求完成一次嘗試的時間長度。 -
apiCallTimeout– 用戶端完全執行 API 呼叫所需的時間量。這包括由所有 HTTP 請求組成的請求處理常式執行,包括重試。
AWS SDK for Java 2.x 提供一些逾時選項的預設值ClientOverrideConfiguration 中設定這些逾時,則 SDK 會使用通訊端逾時值,而非整體 API 呼叫逾時。通訊端的預設逾時值為 30 秒。
RetryMode
另一個與您應該考慮的逾時組態相關的組態是 RetryMode 組態物件。此組態物件包含重試行為的集合。
適用於 Java 2.x 的 SDK 支援下列重試模式:
-
legacy– 如果您未明確變更,預設的重試模式。此重試模式專屬於 Java SDK。它的特徵是最多 3 次重試,或對於 DynamoDB 等服務有 8 次重試。 -
standard– 命名為「標準」,因為它更符合其他 AWS SDKs。此模式會等待從 0 毫秒到 1,000 毫秒的隨機時間量進行第一次重試。如果需要重試,則此模式會挑選從 0 毫秒到 1,000 毫秒的另一個隨機時間,並將其乘以 2。如果需要額外的重試,則會執行相同的隨機挑選值乘以 4,依此類推。每次等待上限為 20 秒。相較於legacy模式,此模式在偵測到時會執行重試的失敗條件更多。對於 DynamoDB,除非您使用 numRetries 覆寫,否則它最多會執行總共 3 次嘗試。 -
adaptive– 以standard模式為基礎,並動態限制 AWS 請求率,使成功率最大化。這可能會因為請求延遲而發生。當可預測延遲很重要時,我們不建議使用自適應重試模式。
您可以在 AWS SDK 和工具參考指南的重試行為主題中找到這些重試模式的擴展定義。
重試政策
所有 RetryMode 組態都有以一或多個 RetryConditionRetryPolicyTokenBucketRetryConditionTokenBucket 中減去權杖。
當用戶端遇到可重試的錯誤,例如限流例外狀況或暫時性伺服器錯誤時,SDK 會自動重試請求。您可以控制這些重試的次數和速度。
設定用戶端時,您可以提供支援下列參數的 RetryPolicy:
-
numRetries– 請求視為失敗之前應套用的重試次數上限。無論您使用的重試模式為何,預設值都是 8。警告
請務必在適當考量後變更此預設值。
-
backoffStrategy– 要套用至重試的BackoffStrategy,預設策略為 FullJitterBackoffStrategy。此策略會根據目前的次數或重試次數、基本延遲和最大退避時間,在額外重試之間執行指數延遲。然後,它會新增抖動以提供一點隨機性。無論重試模式為何,指數延遲中使用的基本延遲為 25 毫秒。 -
retryCondition–RetryCondition決定要不要重試請求。根據預設,它會重試一組特定的 HTTP 狀態碼,以及其認為可重試的例外狀況。在大多數情況下,預設組態應已足夠。
下列程式碼提供替代的重試政策。它總共指定 5 次重試 (總共 6 個請求)。第一次重試應該在延遲大約 100 毫秒之後進行,每次額外的重試都會將該時間以指數方式倍增,最多延遲一秒鐘。
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
ClientOverrideConfiguration 和 RetryMode 不管理的逾時屬性通常透過指定 DefaultsMode 來隱含設定。
AWS SDK for Java 2.x (2.17.102 版或更新版本) 推出對 的支援DefaultsMode。此功能為常見的可配置設定提供一組預設值,例如 HTTP 通訊設定、重試行為、服務區域端點設定,以及可能的任何 SDK 相關組態。使用此功能時,您可以取得針對常見使用案例量身打造的新組態預設值。
預設模式會跨所有 AWS SDKs標準化。適用於 Java 2.x 的 SDK 支援下列預設模式:
-
legacy– 提供預設設定,這些設定會因 AWS SDK 而異,而且在DefaultsMode建立之前已存在。 -
standard– 提供大多數案例的預設非最佳化設定。 -
in-region– 以標準模式為基礎,並包含為 AWS 服務 在相同 內呼叫的應用程式量身打造的設定 AWS 區域。 -
cross-region– 以標準模式為基礎,並為在不同區域中呼叫 AWS 服務 的應用程式提供具有高逾時值的設定。 -
mobile– 以標準模式為基礎,並為具有較高延遲的行動應用程式提供量身打造的高逾時設定。 -
auto– 以標準模式為基礎,並包含實驗性功能。SDK 會嘗試探索執行時期環境,自動判斷適當的設定。自動偵測是以啟發式為基礎,不提供 100% 的準確性。如果無法判斷執行時期環境,則會使用標準模式。自動偵測可能會查詢執行個體中繼資料和使用者資料,這可能會導致延遲。如果啟動延遲對您的應用程式至關重要,我們建議您改為明確選擇DefaultsMode。
您可以透過下列方式設定預設模式:
-
直接在用戶端上,透過
AwsClientBuilder.Builder#defaultsMode(DefaultsMode)。 -
在組態設定檔上,透過
defaults_mode設定檔檔案屬性。 -
全域,透過
aws.defaultsMode系統屬性。 -
全域,透過
AWS_DEFAULTS_MODE環境變數。
注意
對於 legacy 以外的任何模式,附加的預設值可能會隨著最佳實務的演進而變更。因此,如果您使用的是 legacy 以外的模式,建議您在升級 SDK 時執行測試。
AWS SDK 和工具參考指南中的智慧組態預設會以不同的預設模式提供組態屬性及其預設值的清單。
您可以根據應用程式的特性和應用程式互動的 AWS 服務 來選擇預設模式值。
這些值的設定考量了 的廣泛選擇 AWS 服務 。對於 DynamoDB 資料表和應用程式都部署在一個區域中的典型 DynamoDB 部署,in-region 預設模式在 standard 預設模式之間最為相關。
範例 DynamoDB SDK 用戶端組態已針對低延遲呼叫進行調校
下列範例會將逾時調整為預期低延遲 DynamoDB 呼叫的較低值。
DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.builder() .defaultsMode(DefaultsMode.IN_REGION) .httpClientBuilder(AwsCrtAsyncHttpClient.builder()) .overrideConfiguration(ClientOverrideConfiguration.builder() .apiCallTimeout(Duration.ofSeconds(3)) .apiCallAttemptTimeout(Duration.ofMillis(500)) .build()) .build();
個別 HTTP 用戶端實作可能會為您提供對逾時和連線使用行為的更精細控制。例如,對於以 AWS CRT 為基礎的用戶端,您可以啟用 ConnectionHealthConfiguration,讓用戶端主動監控已使用連線的運作狀態。如需詳細資訊,請參閱《 AWS SDK for Java 2.x 開發人員指南》中的 AWS CRT 型 HTTP 用戶端的進階組態。
Keep-Alive 組態
啟用保持連線可以透過重複使用連線來減少延遲。有兩種不同類型的保持連線:HTTP Keep-Alive 和 TCP Keep-Alive。
-
HTTP Keep-Alive 會嘗試維護用戶端和伺服器之間的 HTTPS 連線,以便稍後的請求可以重複使用該連線。這會略過稍後請求的重型 HTTPS 身分驗證。HTTP Keep-Alive 預設為在所有用戶端上啟用。
-
TCP Keep-Alive 請求基礎作業系統透過通訊端連線傳送小型封包,以提供通訊端保持運作的額外保證,並立即偵測任何封包丟失。這可確保稍後的請求不會花時間嘗試使用被捨棄的通訊端。預設會針對所有用戶端停用 TCP Keep-Alive。下列程式碼範例示範如何在每個 HTTP 用戶端上啟用它。針對所有非 CRT 型 HTTP 用戶端啟用時,實際的 Keep-Alive 機制取決於作業系統。因此,您必須透過作業系統設定額外的 TCP Keep-Alive 值,例如逾時和封包數量。您可以在 Linux 或 macOS 上使用
sysctl,或在 Windows 上使用登錄值來執行此操作。
範例 在 Apache 型 HTTP 用戶端上啟用 TCP Keep-Alive
DynamoDbClient client = DynamoDbClient.builder() .httpClientBuilder(ApacheHttpClient.builder().tcpKeepAlive(true)) .build();
URLConnection 型 HTTP 用戶端
任何使用 URLConnection 型 HTTP 用戶端的同步用戶端 HttpURLConnection
範例 在 Netty 型 HTTP 用戶端上啟用 TCP Keep-Alive
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder() .httpClientBuilder(NettyNioAsyncHttpClient.builder().tcpKeepAlive(true)) .build();
範例 在 AWS CRT 型 HTTP 用戶端上啟用 TCP Keep-Alive
使用 AWS CRT 型 HTTP 用戶端,您可以啟用 TCP 保持連線並控制持續時間。
DynamoDbClient client = DynamoDbClient.builder() .httpClientBuilder(AwsCrtHttpClient.builder() .tcpKeepAliveConfiguration(TcpKeepAliveConfiguration.builder() .keepAliveInterval(Duration.ofSeconds(50)) .keepAliveTimeout(Duration.ofSeconds(5)) .build())) .build();
使用非同步 DynamoDB 用戶端時,您可以啟用 TCP Keep-Alive,如下列程式碼所示。
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder() .httpClientBuilder(AwsCrtAsyncHttpClient.builder() .tcpKeepAliveConfiguration(TcpKeepAliveConfiguration.builder() .keepAliveInterval(Duration.ofSeconds(50)) .keepAliveTimeout(Duration.ofSeconds(5)) .build())) .build();
錯誤處理
處理例外狀況時, AWS SDK for Java 2.x 會使用執行時間 (未勾選) 例外狀況。
涵蓋所有 SDK 例外狀況的基本例外狀況是 SdkServiceExceptionRuntimeException。如果您發現這種情況,您將會擷取到 SDK 擲回的所有例外狀況。
SdkServiceException 具有名為 AwsServiceExceptionDynamoDbException
在 DynamoDbException 下有更具體的例外狀況類型TableAlreadyExistsException
-
ConditionalCheckFailedException:您已指定評估為 false 的條件。例如,您可能已嘗試對項目執行條件式更新,但屬性的實際值不符合條件中的預期值。以此方式失敗的請求不會重試。
其他情況則未定義特定的例外狀況。例如,當您的請求受到限流時,可能會擲回特定 ProvisionedThroughputExceededException,而在其他情況下則擲回更通用的 DynamoDbException。在任何一種情況下,您都可以檢查 isThrottlingException() 是否傳回 true,以判斷限流是否造成例外狀況。
根據您的應用程式需求,您可以擷取所有 AwsServiceException 或 DynamoDbException 執行個體。不過,在不同的情況下,您通常需要不同的行為。處理條件檢查失敗的邏輯與處理限流的邏輯不同。定義您要處理的例外路徑,並務必測試替代路徑。這可協助您確保可以處理所有相關案例。
如需可能遇到的常見錯誤清單,請參閱 使用 DynamoDB 時發生錯誤。另請參閱《Amazon DynamoDB API 參考》中的常見錯誤。API 參考也為每個 API 操作 (例如 Query 操作) 提供可能的確切錯誤。如需處理例外狀況的資訊,請參閱《AWS SDK for Java 2.x 開發人員指南》中的 AWS SDK for Java 2.x例外狀況處理。
AWS 請求 ID
每個請求都包含一個請求 ID,如果您使用 AWS 支援 來診斷問題,這對於提取該 ID 很有幫助。衍生自 SdkServiceException 的每個例外狀況都有可用來擷取請求 ID 的 requestId()
日誌
使用 SDK 提供的日誌記錄,對於從用戶端程式庫擷取任何重要訊息以及更深入的偵錯目的都很有用。記錄器是階層式的,SDK 使用 software.amazon.awssdk 做為其根記錄器。您可以使用 TRACE、DEBUG、INFO、WARN、ERROR、ALL 或 OFF 其中之一來設定層級。設定的層級會套用至該記錄器,並沿著記錄器階層向下套用。
對於其記錄, AWS SDK for Java 2.x 使用適用於 Java 的 Simple Logging Façade (SLF4J)。這可做為其他記錄器周圍的抽象層,您可以使用它來插入您偏好的記錄器。如需有關插入記錄器的說明,請參閱 SLF4J 使用者手冊
每個記錄器都有特定的行為。根據預設,Log4j 2.x 記錄器會建立 ConsoleAppender,其會將日誌事件附加至 System.out,並預設為 ERROR 日誌層級。
SLF4J 輸出中包含的 SimpleLogger 記錄器預設為 System.err,並預設為 INFO 日誌層級。
對於任何生產部署,建議您將 WARN 的階層設定為 software.amazon.awssdk,以便從 SDK 的用戶端程式庫擷取任何重要訊息,同時限制輸出數量。
如果 SLF4J 在類別路徑上找不到支援的記錄器 (無 SLF4J 繫結),則會預設為無操作實作System.err,說明 SLF4J 在 classpath 上找不到記錄器實作。若要避免這種情況,您必須新增記錄器實作。若要這樣做,您可以在 Apache Maven pom.xml 中新增對成品的相依性,例如 org.slf4j.slf4j-simple 或 org.apache.logging.log4j.log4j-slf4j2-imp。
如需有關如何在 SDK 中設定記錄的資訊,包括將記錄相依性新增至應用程式組態,請參閱《適用於 Java 的 AWS SDK 開發人員指南》中的使用適用於 Java 2.x 的 SDK 記錄。
如果您使用 Apache Log4j 2 記錄器,Log4j2.xml 檔案中的下列組態顯示如何調整記錄行為。此組態會將根記錄器層級設定為 WARN。階層中的所有記錄器都會繼承此記錄層級,包括 software.amazon.awssdk 記錄器。
根據預設,輸出會移至 System.out。在下列範例中,我們仍會覆寫預設輸出 Log4j 附加元件,以套用量身打造的 Log4j PatternLayout。
Log4j2.xml 組態檔案的 範例
下列組態會在所有記錄器階層的 ERROR 和 WARN 層級將訊息記錄到主控台。
<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>
AWS 請求 ID 記錄
當發生問題時,您可以在例外狀況中找到請求 ID。不過,如果您想要未產生例外狀況的請求 ID,則可以使用記錄功能。
software.amazon.awssdk.request 記錄器會在 DEBUG 層級輸出請求 ID。下列範例延伸先前的 configuration example,將根記錄器層級保持在 ERROR、將 software.amazon.awssdk 保持在層級 WARN,以及將 software.amazon.awssdk.request 保持在層級 DEBUG。設定這些層級有助於擷取請求 ID 和其他請求相關詳細資訊,例如端點和狀態碼。
<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>
以下為日誌輸出的範例:
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
分頁
有些請求,例如 Query 和 Scan,會限制單一請求傳回的資料大小,並要求您重複提出請求以提取後續頁面。
您可以使用 Limit 參數控制每個頁面要讀取的項目數量上限。例如,您可以使用 Limit 參數僅擷取最後 10 個項目。此限制指定套用任何篩選之前要從資料表讀取的項目數量。如果您在篩選後只想要 10 個項目,則無法指定該項目數。您只能控制預先篩選的計數,並在實際擷取 10 個項目時在用戶端檢查。無論限制為何,回應的大小上限一律為 1 MB。
API 回應中可能包含 LastEvaluatedKey。這表示回應因為達到計數限制或大小限制而結束。此金鑰是針對該回應評估的最後一個金鑰。透過直接與 API 互動,您可以擷取此 LastEvaluatedKey,並將其傳遞至後續呼叫做為 ExclusiveStartKey,以便從該起點讀取下一個區塊。如果沒有傳回任何 LastEvaluatedKey,表示沒有更多符合 Query 或 Scan API 呼叫的項目。
下列範例使用低階介面,根據 keyConditionExpression 參數將項目限制為 100。
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()); }
AWS SDK for Java 2.x 可以透過提供自動分頁方法,進行多次服務呼叫,以自動為您取得後續頁面的結果,簡化與 DynamoDB 的互動。這樣可以簡化您的程式碼,但它也移除了手動讀取頁面時所能保持對資源用量的一些控制。
透過使用 DynamoDB 用戶端中可用的 Iterable 方法,例如 QueryPaginatorScanPaginatorQueryPaginator 的結果,如下列範例所示。
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();
資料類別註釋
Java SDK 提供數個註釋,您可以將這些註釋放在資料類別的屬性上。這些註釋會影響 SDK 如何與屬性互動。透過新增註釋,您可以讓屬性做為隱含原子計數器、維護自動產生的時間戳記值,或追蹤項目版本號碼。如需詳細資訊,請參閱資料類別註釋。