

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 DynamoDB 和 AWS SDKs程式設計
<a name="Programming"></a>

本節涵蓋開發人員相關的主題。如果您要改為執行程式碼範例，請參閱[執行此開發人員指南中的程式碼範例](CodeSamples.md)。

**注意**  
2017 年 12 月， AWS 開始遷移所有 Amazon DynamoDB 端點以使用 Amazon Trust Services (ATS) 發行的安全憑證的程序。如需詳細資訊，請參閱[使用 DynamoDB 對 SSL/TLS 連線建立問題進行疑難排解](ats-certs.md)。

**Topics**
+ [DynamoDB 的 AWS SDK 支援概觀](Programming.SDKOverview.md)
+ [使用 Python 和 Boto3 為 Amazon DynamoDB 編寫程式](programming-with-python.md)
+ [使用 JavaScript 編寫 Amazon DynamoDB 程式](programming-with-javascript.md)
+ [使用 程式設計 DynamoDB AWS SDK for Java 2.x](ProgrammingWithJava.md)
+ [使用 DynamoDB 時發生錯誤](Programming.Errors.md)
+ [搭配 AWS SDK 使用 DynamoDB](sdk-general-information-section.md)

# DynamoDB 的 AWS SDK 支援概觀
<a name="Programming.SDKOverview"></a>

下圖提供使用 AWS SDKs 的 Amazon DynamoDB 應用程式程式設計的高階概觀。

![\[搭配 SDK 使用 DynamoDB 的程式設計模型。 AWS SDKs\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/SDKSupport.png)


1. 您可以使用適用於程式設計語言的 AWS 開發套件撰寫應用程式。

1. 每個 AWS SDK 提供一或多個程式設計界面，以使用 DynamoDB。可用的特定界面取決於您使用的程式設計語言和 AWS SDK。選項包括：
   + [使用 DynamoDB 的低階介面](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.LowLevel)
   + [使用 DynamoDB 的文件介面](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.Document)
   + [使用 DynamoDB 的物件持久性介面](Programming.SDKs.Interfaces.md#Programming.SDKs.Interfaces.Mapper)
   + [高階介面](HigherLevelInterfaces.md)

1. SDK AWS 建構 HTTP(S) 請求，以搭配低階 DynamoDB API 使用。

1. SDK 會將請求 AWS 傳送至 DynamoDB 端點。

1. DynamoDB 會執行請求。如果請求成功，DynamoDB 會傳回 HTTP 200 回應代碼 (OK)。如果請求不成功，DynamoDB 會傳回 HTTP 錯誤代碼和錯誤訊息。

1.  AWS SDK 會處理回應並將其傳播回您的應用程式。

每個 AWS SDKs都為您的應用程式提供重要的服務，包括下列項目：
+ 格式化 HTTP(S) 請求和序列化請求參數。
+ 為每個請求產生密碼編譯簽章。
+ 將請求轉寄至 DynamoDB 端點，並接收來自 DynamoDB 的回應。
+ 從這些回應中提取結果。
+ 在出現錯誤的情況下實作基本重試邏輯。

您不需要為上述任何任務編寫程式碼。

**注意**  
如需 AWS SDKs的詳細資訊，包括安裝指示和文件，請參閱[適用於 Amazon Web Services 的工具](https://aws.amazon.com/tools)。

## AWS 支援帳戶型端點的 SDK
<a name="Programming.SDKs.endpoints"></a>

AWS 已在 AWS 2024 年 9 月 4 日推出適用於 DynamoDB 帳戶型端點的 SDK 支援，從適用於 Java 的 AWS SDK V1 開始。這些新端點 AWS 有助於確保高效能和可擴展性。更新的 SDK 會自動使用格式為 `https://(account-id).ddb.(region).amazonaws.com` 的新端點。

如果您使用 SDK 用戶端的單一執行個體向多個帳戶提出請求，您的應用程式重複使用連線的機會會較少。 AWS 建議修改您的應用程式，以連接至每個 SDK 用戶端執行個體的較少帳戶。另一種方法是將 SDK 用戶端設定為使用 `ACCOUNT_ID_ENDPOINT_MODE` 設定繼續使用區域端點，如 [https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html)中所述。

# 使用 DynamoDB 的程式設計介面
<a name="Programming.SDKs.Interfaces"></a>

每個 [AWS 軟體開發套件](https://aws.amazon.com/tools)提供一或多個程式化介面，以便與 Amazon DynamoDB 搭配使用。這些介面範圍從簡單的低階 DynamoDB 包裝函式到物件導向的持久性層。可用的界面會根據您使用的 AWS SDK 和程式設計語言而有所不同。

![\[可用於 DynamoDB 的不同 AWS SDKs的程式設計界面。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/SDKSupport.SDKInterfaces.png)


下一節會以 適用於 Java 的 AWS SDK 為範例來重點介紹一些可用的介面。(並非全部介面都可用於所有 AWS 軟體開發套件。)

**Topics**
+ [使用 DynamoDB 的低階介面](#Programming.SDKs.Interfaces.LowLevel)
+ [使用 DynamoDB 的文件介面](#Programming.SDKs.Interfaces.Document)
+ [使用 DynamoDB 的物件持久性介面](#Programming.SDKs.Interfaces.Mapper)

## 使用 DynamoDB 的低階介面
<a name="Programming.SDKs.Interfaces.LowLevel"></a>

每個語言特定的 AWS SDK 都為 Amazon DynamoDB 提供低階介面，方法與低階 DynamoDB API 請求非常相似。

在某些情況下，您需要識別使用 [資料類型描述項](Programming.LowLevelAPI.md#Programming.LowLevelAPI.DataTypeDescriptors) 的屬性資料類型，例如，適用於字串的 `S` 或適用於數字的 `N`。

**注意**  
每種語言特定的 AWS 軟體開發套件都提供低階介面。

下列 Java 程式使用 適用於 Java 的 AWS SDK的低階介面。

### 低階介面範例
<a name="low-level-example"></a>

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

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

                Usage:
                    <tableName> <key> <keyVal>

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

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

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

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

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

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

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

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

## 使用 DynamoDB 的文件介面
<a name="Programming.SDKs.Interfaces.Document"></a>

 AWS SDKs提供文件界面，可讓您對資料表和索引執行資料平面操作 （建立、讀取、更新、刪除）。使用文件介面時，您不需要指定 [資料類型描述項](Programming.LowLevelAPI.md#Programming.LowLevelAPI.DataTypeDescriptors)。資料類型是由資料本身的語義隱含的。這些 AWS SDKs也提供方法，可輕鬆將 JSON 文件轉換為原生 Amazon DynamoDB 資料類型。

**注意**  
文件界面可在適用於 [ Java](https://aws.amazon.com/sdk-for-java)、.[NET](https://aws.amazon.com/sdk-for-net)、[Node.js](https://aws.amazon.com/sdk-for-node-js) 和 [JavaScript SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/) AWS SDKs 中使用。

下列 Java 程式使用 適用於 Java 的 AWS SDK的文件介面。程式會建立代表 `Music` 資料表的 `Table` 物件，然後要求該物件使用 `GetItem` 來擷取歌曲。然後程式會列印歌曲發行的年份。

`software.amazon.dynamodb.document.DynamoDB` 類別會實作 DynamoDB 文件介面。請注意 `DynamoDB` 作為低階用戶端 (`AmazonDynamoDB`) 包裝函式的方式。

### 文件介面範例
<a name="document-level-example"></a>

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

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

public class MusicDocumentDemo {

    public static void main(String[] args) {

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

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

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

    }
}
```

## 使用 DynamoDB 的物件持久性介面
<a name="Programming.SDKs.Interfaces.Mapper"></a>

 AWS SDKs提供物件持久性界面，您不會在其中直接執行資料平面操作。反之，您要建立代表 Amazon DynamoDB 資料表和索引中項目的物件，並且僅與這些物件互動。這允許您編寫以物件為中心的程式碼，而不是以資料庫為中心的程式碼。

**注意**  
適用於 Java 和 .NET AWS SDKs 中提供物件持久性界面。如需詳細資訊，請參閱適用於 DynamoDB 的 [適用於 DynamoDB 的更高階程式設計界面](HigherLevelInterfaces.md)。

### 物件持久性介面
<a name="mapper-level-example"></a>

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

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

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

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

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

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

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

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

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

# 適用於 DynamoDB 的更高階程式設計界面
<a name="HigherLevelInterfaces"></a>

 AWS SDKs 為應用程式提供使用 Amazon DynamoDB 的低階界面。這些用戶端類別和方法直接對應至低階 DynamoDB API。不過，當需要將複雜的資料類型映射至資料庫資料表中的項目時，許多開發人員會遭遇到網路斷線的感覺，或*阻抗不符*。使用低階資料庫界面，開發人員必須撰寫讀取或寫入物件資料至資料庫資料表的方法，反之亦然。物件類型和資料庫表格每個組合所需的額外程式碼數量似乎非常大。

為了簡化開發，適用於 Java 和 .NET AWS SDKs 提供額外的介面，具有更高層級的抽象。DynamoDB 的較高階界面可讓您定義程式中的物件與存放這些物件資料的資料庫表格之間的關係。定義此映射之後，您可以呼叫簡單的物件方法 (例如 `save`、`load` 或 `delete`)，也可以代表您自動叫用基礎低階 DynamoDB 操作。這允許您編寫以物件為中心的程式碼，而不是以資料庫為中心的程式碼。

DynamoDB 的高階程式設計界面可在適用於 Java 和 .NET AWS SDKs 中使用。

**Java**
+ [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)
+ [Java 2.x：DynamoDB 增強型用戶端](DynamoDBEnhanced.md)

**.NET**
+ [在 DynamoDB 中使用 .NET 文件模型](DotNetSDKMidLevel.md)
+ [使用 .NET 物件持久性模型和 DynamoDB](DotNetSDKHighLevel.md)

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

**注意**  
適用於 Java 的 SDK 有兩個版本：1.x 和 2.x。1.x 版本已於 2024 年 1 月 12 日[宣布](https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-java-v1-x-on-december-31-2025/)終止支援。該版本將於 2025 年 12 月 31 日到期並終止支援。我們強烈建議您在新的開發作業使用 2.x 版本。

 適用於 Java 的 AWS SDK 提供 `DynamoDBMapper`類別，可讓您將用戶端類別映射至 Amazon DynamoDB 資料表。若要使用 `DynamoDBMapper`，請定義 DynamoDB 資料表中項目與程式碼中其對應物件執行個體之間的關係。`DynamoDBMapper` 類別也讓您執行各種建立、讀取、更新和對項目進行刪除 (CRUD) 操作，以及執行查詢和掃描資料表。

**Topics**
+ [DynamoDBMapper Class](DynamoDBMapper.Methods.md)
+ [適用於 Java 的 DynamoDBMapper 支援的資料類型](DynamoDBMapper.DataTypes.md)
+ [適用於 DynamoDB 的 Java 註釋](DynamoDBMapper.Annotations.md)
+ [DynamoDBMapper 的選用組態設定](DynamoDBMapper.OptionalConfig.md)
+ [含版本編號的 DynamoDB 及樂觀鎖定](DynamoDBMapper.OptimisticLocking.md)
+ [在 DynamoDB 中映射任意資料](DynamoDBMapper.ArbitraryDataMapping.md)
+ [DynamoDBMapper 範例](DynamoDBMapper.Examples.md)

**注意**  
`DynamoDBMapper` 類別不允許您建立、更新或刪除資料表。若要執行這些任務，請改為使用低階適用於 Java 的開發套件介面。

適用於 Java 的開發套件提供一組註釋類型，讓您可以將類別映射至資料表。例如，考量其 `Id` 為分割區索引鍵的 `ProductCatalog` 資料表。

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

您可以將用戶端應用程式中的類別映射至 `ProductCatalog` 資料表，如下列 Java 程式碼所示。此程式碼定義名為 `CatalogItem` 的純舊 Java 物件 (POJO)，而此物件使用註釋將物件欄件映射至 DynamoDB 屬性名稱。

**Example**  

```
package com.amazonaws.codesamples;

import java.util.Set;

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

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

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

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

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

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

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

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

在上述程式碼中，`@DynamoDBTable` 註釋會將 `CatalogItem` 類別映射至 `ProductCatalog` 資料表。您可以將個別類別執行個體存放為資料表中的項目。在類別定義中，`@DynamoDBHashKey` 註釋會將 `Id` 屬性映射至主索引鍵。

類別屬性預設會映射至資料表中的相同名稱屬性。`Title` 和 `ISBN` 屬性會映射至資料表中的相同名稱屬性。

DynamoDB 屬性的名稱符合類別中所宣告屬性的名稱時，`@DynamoDBAttribute` 註釋是選用項目。它們不同時，請搭配使用此註釋與 `attributeName` 參數，指定此屬性所對應的 DynamoDB 屬性。

在上述範例中，將 `@DynamoDBAttribute` 註釋新增至每個屬性，確保屬性名稱完全符合前個步驟中所建立的資料表，並與本指南的其他程式碼範例中所使用的屬性名稱一致。

類別定義可以有未映射至資料表中任何屬性的屬性。您可以新增 `@DynamoDBIgnore` 註釋來識別這些屬性。在上述範例中，`SomeProp` 屬性會標上 `@DynamoDBIgnore` 註釋。當您將 `CatalogItem` 執行個體上傳至資料表時，`DynamoDBMapper` 執行個體不會包含 `SomeProp` 屬性。此外，當您從資料表中擷取項目時，映射器不會傳回此屬性。

在您定義映射類別之後，可以使用 `DynamoDBMapper` 方法，將該類別的執行個體寫入至 `Catalog` 資料表中的對應項目。以下程式碼範例會示範此技術。

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

DynamoDBMapper mapper = new DynamoDBMapper(client);

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

mapper.save(item);
```

下列程式碼範例示範如何擷取項目以及存取它的一些屬性：

```
CatalogItem partitionKey = new CatalogItem();

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

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

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

`DynamoDBMapper` 提供直觀且自然的方式來處理 Java 內的 DynamoDB 資料。它也提供數項內建功能；例如，樂觀鎖定、ACID 交易、自動產生的分割區索引鍵和排序索引鍵值，以及物件版本控制。

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



`DynamoDBMapper` 類別是 Amazon DynamoDB 的進入點。它提供 DynamoDB 端點的存取，也讓您可以存取多個資料表中的資料。它也讓您執行各種建立、讀取、更新和對項目進行刪除 (CRUD) 操作，以及執行查詢和掃描資料表。此類別提供下列使用 DynamoDB 的方法。

如需對應的 Javadoc 文件，請參閱《適用於 Java 的 AWS SDK API 參考》**中的 [DynamoDBMapper](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html)。

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

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

將指定的物件儲存至資料表。您要儲存的物件是此方法的唯一必要參數。您可以使用 `DynamoDBMapperConfig` 物件來提供選用的組態參數。

如果具有相同主索引鍵的項目不存在，則此方法會在資料表中建立新的項目。如果具有相同主索引鍵的項目存在，則會更新現有項目。如果分割區索引鍵和排序索引鍵的類型是字串，並且標註 `@DynamoDBAutoGeneratedKey`，則會將隨機全域唯一識別符 (UUID) 授予它們 (若未初始化)。標註 `@DynamoDBVersionAttribute` 的版本欄位會遞增一。此外，如果更新版本欄位或產生索引鍵，則會因這項操作而更新傳入的物件。

根據預設，只會更新對應至已映射類別屬性的屬性。項目上的任何其他現有屬性則不受影響。不過，如果您指定 `SaveBehavior.CLOBBER`，則可以強制完全覆寫項目。

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

如果您已啟用版本控制，則用戶端與伺服器端項目版本必須相符。不過，如果使用 `SaveBehavior.CLOBBER` 選項，則版本不需要相符。如需版本控制的詳細資訊，請參閱「[含版本編號的 DynamoDB 及樂觀鎖定](DynamoDBMapper.OptimisticLocking.md)」。

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

從資料表擷取項目。您必須提供要擷取之項目的主索引鍵。您可以使用 `DynamoDBMapperConfig` 物件來提供選用的組態參數。例如，您可以選擇性地請求高度一致性讀取，確保此方法只擷取最新的項目數值，如下列 Java 陳述式所示。

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

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

DynamoDB 預設會傳回數值最終一致的項目。如需 DynamoDB 最終一致性模式的資訊，請參閱 [DynamoDB 讀取一致性](HowItWorks.ReadConsistency.md)。

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

刪除資料表中的項目。您必須傳入已映射類別的物件執行個體。

如果您已啟用版本控制，則用戶端與伺服器端項目版本必須相符。不過，如果使用 `SaveBehavior.CLOBBER` 選項，則版本不需要相符。如需版本控制的詳細資訊，請參閱「[含版本編號的 DynamoDB 及樂觀鎖定](DynamoDBMapper.OptimisticLocking.md)」。

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

查詢資料表或次要索引。

假設您有一個存放論壇主題回覆的 `Reply` 資料表。每個對話主旨都可以有零個以上的回覆。`Reply` 資料表的主索引鍵包含 `Id` 和 `ReplyDateTime` 欄位；其中，`Id` 是分割區索引鍵，而 `ReplyDateTime` 是主索引鍵的排序索引鍵。

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

假設您已建立 `Reply` 類別與 DynamoDB 中對應 `Reply` 資料表之間的映射。下列 Java 程式碼使用 `DynamoDBMapper` 來尋找特定對話主旨在過去兩週的所有回覆。

**Example**  

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

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

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

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

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

查詢會傳回 `Reply` 物件的集合。

`query` 方法預設會傳回「延遲載入」集合。它一開始只會傳回一頁的結果，然後視需要進行服務呼叫來取得下一頁。若要取得所有相符的項目，請逐一查看 `latestReplies` 集合。

請注意，在集合上呼叫 `size()` 方法將會載入所有結果，以提供準確的計數。這可能會導致耗用大量已佈建的輸送量，而在非常大型的資料表上可能甚至會耗盡 JVM 中的所有記憶體。

若要查詢索引，您必須先將索引建模為映射器類別。假設 `Reply` 資料表有一個名為 *PostedBy-Message-Index* 的全域次要索引。此索引的分割區索引鍵是 `PostedBy`，而排序索引鍵是 `Message`。索引中項目的類別定義將會如下。

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

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

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

   // Additional properties go here.
}
```

`@DynamoDBTable` 註釋指出此索引與 `Reply` 資料表建立關聯。`@DynamoDBIndexHashKey` 註釋表示索引的分割區索引鍵 (*PostedBy*)，而 `@DynamoDBIndexRangeKey` 表示索引的排序索引鍵 (*Message*)。

您現在可以使用 `DynamoDBMapper` 來查詢索引，並擷取特定使用者所張貼的訊息子集。如果資料表和索引之間沒有衝突的映射，且映射器中已建立映射，則不需要指定索引名稱。映射器將根據主索引鍵和排序索引鍵推論。下列程式碼會查詢全域次要索引。因為全域次要索引支援最終一致讀取，但不支援高度一致性讀取，所以必須指定 `withConsistentRead(false)`。

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

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

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

查詢會傳回 `PostedByMessage` 物件的集合。

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

查詢資料表或次要索引，並傳回單頁的相符結果。與使用 `query` 方法相同，您必須指定分割區索引鍵值以及套用至排序索引鍵屬性的查詢篩選條件。不過，`queryPage` 只會傳回第一「頁」的資料；亦即，符合 1 MB 的資料量 

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

掃描整個資料表或次要索引。您可以選擇性地指定 `FilterExpression` 來篩選結果集。

假設您有一個存放論壇主題回覆的 `Reply` 資料表。每個對話主旨都可以有零個以上的回覆。`Reply` 資料表的主索引鍵包含 `Id` 和 `ReplyDateTime` 欄位；其中，`Id` 是分割區索引鍵，而 `ReplyDateTime` 是主索引鍵的排序索引鍵。

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

如果您已將 Java 類別映射至 `Reply` 資料表，則可以使用 `DynamoDBMapper` 來掃描資料表。例如，下列 Java 程式碼會掃描整個 `Reply` 資料表，而且只會傳回特定一年的回覆。

**Example**  

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

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

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

`scan` 方法預設會傳回「延遲載入」集合。它一開始只會傳回一頁的結果，然後視需要進行服務呼叫來取得下一頁。若要取得所有相符的項目，請逐一查看 `replies` 集合。

請注意，在集合上呼叫 `size()` 方法將會載入所有結果，以提供準確的計數。這可能會導致耗用大量已佈建的輸送量，而在非常大型的資料表上可能甚至會耗盡 JVM 中的所有記憶體。

若要掃描索引，您必須先將索引建模為映射器類別。假設 `Reply` 資料表有一個名為 `PostedBy-Message-Index` 的全域次要索引。此索引的分割區索引鍵是 `PostedBy`，而排序索引鍵是 `Message`。此索引的映射器類別顯示在 [query](#DynamoDBMapper.Methods.query) 區段。它使用 `@DynamoDBIndexHashKey` 和 `@DynamoDBIndexRangeKey` 註釋來指定索引的分割區索引鍵和排序索引鍵。

下列程式碼範例掃描 `PostedBy-Message-Index`。它不會使用掃描篩選條件，因此會將索引中的所有項目都傳回給您。

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

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

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

掃描資料表或次要索引，並傳回單頁的相符結果。與使用 `scan` 方法相同，您可以選擇性地指定 `FilterExpression` 來篩選結果集。不過，`scanPage` 只會傳回第一「頁」的資料；亦即，符合 1 MB 內的資料量。

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

執行整個資料表或次要索引的平行掃描。您可以指定資料表的一些邏輯區段，以及掃描表達式來篩選結果。`parallelScan` 會將掃描任務分到多個工作者 (一個邏輯區段一個工作者)；工作者會平行處理資料，並傳回結果。

下列 Java 程式碼範例會對 `Product` 資料表執行平行掃描。

```
int numberOfThreads = 4;

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

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

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

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

使用 `AmazonDynamoDB.batchWriteItem` 方法的一或多個呼叫，將物件儲存至一或多個資料表。此方法不提供交易保證。

下列 Java 程式碼會將兩個項目 (書籍) 儲存至 `ProductCatalog` 資料表。

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

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

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

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

使用一或多個資料表的主索引鍵，以從中擷取多個項目。

下列 Java 程式碼會從兩個不同的資料表擷取兩個項目。

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

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

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

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

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

使用 `AmazonDynamoDB.batchWriteItem` 方法的一或多個呼叫，刪除一或多個資料表中的物件。此方法不提供交易保證。

下列 Java 程式碼會刪除 `ProductCatalog` 資料表中的兩個項目 (書籍)。

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

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

使用 `AmazonDynamoDB.batchWriteItem` 方法的一或多個呼叫，將物件儲存至一或多個資料表，並刪除物件。此方法未提供交易保證或支援版本控制 (條件式放置或刪除)。

下列 Java 程式碼會將新項目寫入至 `Forum` 資料表、將新項目寫入至 `Thread` 資料表，並刪除 `ProductCatalog` 資料表中的項目。

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

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

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

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

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

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

使用 `AmazonDynamoDB.transactWriteItems` 方法的一個呼叫，將物件儲存至一或多個資料表，並從中刪除物件。

如需交易特定例外的清單，請參閱 [TransactWriteItems 錯誤](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html#API_TransactWriteItems_Errors)。

如需 DynamoDB 交易與提供之不可部分完成性、一致性、隔離性和耐久性 (ACID) 保證的相關資訊，請參閱 [Amazon DynamoDB Transactions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)。

**注意**  
 此方法不支援下列項目：  
[DynamoDBMapperConfig.SaveBehavior](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptionalConfig.html)。

以下 Java 程式碼會以交易的方式，將新項目寫入每個 `Forum` 和 `Thread` 資料表。

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

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

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

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

使用 `AmazonDynamoDB.transactGetItems` 方法的一個呼叫，載入一或多個資料表中的物件。

如需交易特定例外的清單，請參閱 [TransactGetItems 錯誤](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html#API_TransactGetItems_Errors)。

如需 DynamoDB 交易與提供之不可部分完成性、一致性、隔離性和耐久性 (ACID) 保證的相關資訊，請參閱 [Amazon DynamoDB Transactions](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)。

以下 Java 程式碼會以交易的方式，將從每個 `Forum` 和 `Thread` 資料表載入一個項目。

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

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

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

評估指定的掃描表達式，並傳回相符項目的計數。不傳回任何項目資料。

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

剖析代表 DynamoDB 資料表的 POJO 類別，並傳回該資料表的 `CreateTableRequest`。

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

建立 Amazon S3 中物件的連結。您必須指定儲存貯體名稱和索引鍵名稱，以唯一識別儲存貯體中的物件。

若要使用 `createS3Link`，映射器類別必須定義 getter 和 setter 方法。下列程式碼範例透過將新的屬性和 getter/setter 方法新增至 `CatalogItem` 類別來說明這種情況。

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

    ...

    public S3Link productImage;

    ....

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

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

...
}
```

下列 Java 程式碼定義要寫入至 `Product` 資料表的新項目。此項目包含產品映像的連結；映像資料會上傳至 Amazon S3。

```
CatalogItem item = new CatalogItem();

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

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

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

mapper.save(item);
```

`S3Link` 類別提供許多其他方法來操控 Amazon S3 中的物件。如需詳細資訊，請參閱 [Javadocs for `S3Link`](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/S3Link.html)。

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

傳回基礎 `S3ClientCache` 來存取 Amazon S3。`S3ClientCache` 是 `AmazonS3Client` 物件的智慧映射。如果您有多個用戶端， `S3ClientCache`可協助您依 AWS 區域整理用戶端，並可隨需建立新的 Amazon S3 用戶端。

# 適用於 Java 的 DynamoDBMapper 支援的資料類型
<a name="DynamoDBMapper.DataTypes"></a>

本節說明 Amazon DynamoDB 中支援的基本 Java 資料類型、集合和任意資料類型。

Amazon DynamoDB 支援下列基本 Java 資料類型和基本包裝函式類別。
+ `String`
+ `Boolean`, `boolean`
+ `Byte`, `byte`
+ `Date` (作為 [ISO\$18601](http://en.wikipedia.org/wiki/ISO_8601) 毫秒精確性字串，已轉移為 UTC)
+ `Calendar` (作為 [ISO\$18601](http://en.wikipedia.org/wiki/ISO_8601) 毫秒精確性字串，已轉移為 UTC)
+ `Long`, `long`
+ `Integer`, `int`
+ `Double`, `double`
+ `Float`, `float`
+ `BigDecimal`
+ `BigInteger`

**注意**  
如需有關 DynamoDB 命名規則和各種支援之資料類型的詳細資訊，請參閱 [Amazon DynamoDB 中支援的資料類型和命名規則](HowItWorks.NamingRulesDataTypes.md)。
空白的二進位值由 DynamoDBMapper 支援。
 AWS SDK for Java 2.x支援空白字串值。  
在適用於 Java 的 AWS SDK 1.x 中，DynamoDBMapper 支援讀取空的字串屬性值，但它不會寫入空的字串屬性值，因為這些屬性會從請求中刪除。

DynamoDB 支援 Java [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html)、[List](http://docs.oracle.com/javase/6/docs/api/java/util/List.html) 和 [Map](http://docs.oracle.com/javase/6/docs/api/java/util/Map.html) 集合類型。下表摘要說明如何將這些 Java 類型映射至 DynamoDB 類型。


****  

| Java 類型 | DynamoDB 類型 | 
| --- | --- | 
|  所有數字類型  |  `N` (數字類型)  | 
|  Strings  |  `S` (字串類型)   | 
|  Boolean  |  `BOOL` (布林類型)，0 或 1。  | 
|  ByteBuffer  |  `B` (二進位類型)  | 
|  Date  |  `S` (字串類型)。Date 值會以 ISO-8601 格式字串存放。  | 
| [Set](http://docs.oracle.com/javase/6/docs/api/java/util/Set.html) 集合類型 |  `SS` (字串集) 類型、`NS` (數字集) 類型或 `BS` (二進位集) 類型。  | 

 `DynamoDBTypeConverter` 介面可讓您將自己的任意資料類型映射至 DynamoDB 原生支援的資料類型。如需詳細資訊，請參閱[在 DynamoDB 中映射任意資料](DynamoDBMapper.ArbitraryDataMapping.md)。

# 適用於 DynamoDB 的 Java 註釋
<a name="DynamoDBMapper.Annotations"></a>

本節說明可用於將類別和屬性映射至 Amazon DynamoDB 中資料表和屬性的註釋。

如需對應的 Javadoc 文件，請參閱《[適用於 Java 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdk-for-java/latest/reference/)》中的[註釋類型摘要](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/package-summary.html)。

**注意**  
在下列註釋中，只需要 `DynamoDBTable` 和 `DynamoDBHashKey`。

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

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

將屬性映射至資料表屬性。每個類別屬性預設會映射至同名的項目屬性。不過，如果名稱不同，您可以使用此註釋將屬性 (property) 映射至屬性 (attribute)。在下列 Java 程式碼片段中，`DynamoDBAttribute` 會將 `BookAuthors` 屬性映射至資料表中的 `Authors` 屬性名稱。

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

將物件儲存至資料表時，`DynamoDBMapper` 使用 `Authors` 做為屬性名稱。

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

將分割區索引鍵或排序索引鍵屬性標示為自動產生。儲存這些屬性時，`DynamoDBMapper`​ 會產生隨機 [​UUID](http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html)。只有字串屬性才能標示為自動產生的索引鍵。

以下是示範使用自動產生索引鍵參數的範例。

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

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

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

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

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

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

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

自動產生時間戳記。

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

或者，可以透過提供策略屬性來定義自動產生策略。預設值為 `ALWAYS`。

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

指出類別可以序列化為 Amazon DynamoDB 文件。

例如，假設您要將 JSON 文件映射至 Map (`M`) 類型的 DynamoDB 屬性。下列程式碼範例定義包含 Map 類型之巢狀屬性 (Pictures) 的項目。

```
public class ProductCatalogItem {

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

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

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

    // Additional properties go here.

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

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

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

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

     }
}
```

然後您就可儲存新的 `ProductCatalog` 項目，並具有 `Pictures`，如下列範例所示。

```
ProductCatalogItem item = new ProductCatalogItem();

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

item.setId(123);

mapper.save(item);
```

產生的 `ProductCatalog`項目看起來將會如下 (JSON 格式)。

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

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

將類別屬性映射至資料表的分割區索引鍵。此屬性必須是純量字串、數字或二進位類型的其中之一。此屬性不能是集合類型。

假設您的 `ProductCatalog` 資料表將 `Id` 作為主索引鍵。下列 Java 程式碼定義 `CatalogItem` 類別，並使用 `@DynamoDBHashKey` 標籤將其 `Id` 屬性映射至 `ProductCatalog` 資料表的主索引鍵。

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

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

指出應該忽略相關聯屬性的 `DynamoDBMapper` 執行個體。將資料儲存至資料表時，`DynamoDBMapper` 不會將此屬性儲存至資料表。

 套用至 getter 方法或非模組化屬性的類別欄位。若該註釋是直接套用至類別欄位，則必須在相同的類別宣告相對應的 getter 和 setter。

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

將類別屬性映射至全域次要索引的分割區索引鍵。此屬性必須是純量字串、數字或二進位類型的其中之一。此屬性不能是集合類型。

如果您需要對全域次要索引進行 `Query`，請使用此註釋。您必須指定索引名稱 (`globalSecondaryIndexName`)。如果類別屬性的名稱與索引的分割區索引鍵不同，您也必須指定該索引屬性的名稱 (`attributeName`)。

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

將類別屬性映射至全域次要索引或本機次要索引的排序索引鍵。此屬性必須是純量字串、數字或二進位類型的其中之一。此屬性不能是集合類型。

如果您需要對本機次要索引或全域次要索引進行 `Query`，並且想要使用索引的排序索引鍵來縮小您結果的範圍，請使用此註釋。您必須指定索引名稱 (`globalSecondaryIndexName` 或 `localSecondaryIndexName`)。如果類別屬性的名稱與索引的排序索引鍵不同，您也必須指定該索引屬性的名稱 (`attributeName`)。

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

將類別屬性映射至資料表的排序索引鍵。此屬性必須是純量字串、數字或二進位類型的其中之一。它不能是集合類型。

如果主索引鍵是複合 (分割區索引鍵和排序索引鍵)，您可以使用此標籤，將類別欄位映射至排序索引鍵。例如，假設您的 `Reply` 資料表存放論壇主題回覆。每個對話都可以有許多回覆。因此，此資料表的主索引鍵是 `ThreadId` 和 `ReplyDateTime`。分割區索引鍵是 `ThreadId`，而排序索引鍵是 `ReplyDateTime`。

下列 Java 程式碼定義 `Reply` 類別，並將它映射至 `Reply` 資料表。它會使用 `@DynamoDBHashKey` 和 `@DynamoDBRangeKey` 標籤來識別映射至主索引鍵的類別屬性。

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

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

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

   // Additional properties go here.
}
```

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

識別 DynamoDB 中的目標資料表。下列 Java 程式碼定義 `Developer` 類別，並將它映射至 DynamoDB 中的 `People` 資料表。

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

`@DynamoDBTable` 註釋可以予以繼承。任何繼承自 `Developer` 類別的新類別也會映射至 `People` 資料表。例如，假設您建立繼承自 `Lead` 類別的 `Developer` 類別。因為您已將 `Developer` 類別映射至 `People` 資料表，所以也會將 `Lead` 類別物件存放至相同的資料表。

`@DynamoDBTable` 也可以予以覆寫。任何繼承自 `Developer` 類別的新類別預設會映射至相同的 `People` 資料表。不過，您可以覆寫此預設映射。例如，如果您建立繼承自 `Developer` 類別的類別，則可以新增 `@DynamoDBTable` 註釋，明確地將它映射至另一個資料表，如下列 Java 程式碼範例所示。

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

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

將屬性標示為使用自訂類型轉換器的註釋。可以標註於使用者定義的註釋，以將其他屬性傳遞給 `DynamoDBTypeConverter`。

 `DynamoDBTypeConverter` 介面可讓您將自己的任意資料類型映射至 DynamoDB 原生支援的資料類型。如需詳細資訊，請參閱[在 DynamoDB 中映射任意資料](DynamoDBMapper.ArbitraryDataMapping.md)。

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

覆寫標準屬性類型繫結的註釋。如果套用標準類型的預設屬性繫結，則該類型不需要註釋。

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

識別用於存放樂觀鎖定版本編號的類別屬性。`DynamoDBMapper`​ 在儲存新的項目時會將版本編號指派給此屬性，並在每次您更新項目時予以遞增。僅支援數字純量類型。如需資料類型的詳細資訊，請參閱 [資料類型](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes)。如需版本控制的詳細資訊，請參閱「[含版本編號的 DynamoDB 及樂觀鎖定](DynamoDBMapper.OptimisticLocking.md)」。

# DynamoDBMapper 的選用組態設定
<a name="DynamoDBMapper.OptionalConfig"></a>

當您建立 `DynamoDBMapper` 執行個體時，會有特定預設行為；您可以使用 `DynamoDBMapperConfig` 類別來覆寫這些預設值。

下列程式碼片段會使用自訂設定來建立 `DynamoDBMapper`：

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

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

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

如需詳細資訊，請參閱《[適用於 Java 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdk-for-java/latest/reference/)》中的 [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapperConfig.html)。

您可以針對 `DynamoDBMapperConfig` 執行個體使用下列引數：
+ `DynamoDBMapperConfig.ConsistentReads` 列舉值：
  + `EVENTUAL`：映射器執行個體使用最終一致讀取請求。
  + `CONSISTENT`：映射器執行個體使用高度一致性讀取請求。您可以搭配使用這個選用設定與 `load`、`query` 或 `scan` 操作。高度一致性讀取具有效能和帳單隱憂；如需詳細資訊，請參閱 DynamoDB [產品詳細資訊頁面](https://aws.amazon.com/dynamodb)。

  如果您未指定映射器執行個體的讀取一致性設定，則預設值為 `EVENTUAL`。
**注意**  
此值僅適用於 DynamoDBMapper 的 `query`、`querypage`、`load` 和 `batch load` 操作。
+ `DynamoDBMapperConfig.PaginationLoadingStrategy` 列舉值：控制映射器執行個體如何處理分頁資料清單，例如 `query` 或 `scan` 的結果：
  + `LAZY_LOADING`：映射器執行個體會在可能時載入資料，並將所有載入的結果保留在記憶體中。
  + `EAGER_LOADING`：映射器執行個體會在初始化清單時立即載入資料。
  + `ITERATION_ONLY`：您只能使用從清單中讀取的迭代器。在迭代期間，清單會先清除所有先前的結果，再載入下一頁，因此清單最多會將一頁的已載入結果保留在記憶體中。這也表示清單只能重複使用一次。處理大型項目時，建議使用此策略，以減少記憶體負擔。

  如果您未指定映射器執行個體的分頁載入策略，則預設值為 `LAZY_LOADING`。
+ `DynamoDBMapperConfig.SaveBehavior` 列舉值：指定映射器執行個體在儲存操作期間應該如何處理屬性：
  + `UPDATE`：在儲存操作期間，會更新所有建模屬性，未建模屬性則不受影響。基本數字類型 (byte、int、long) 設定為 0。物件類型設定為 Null。
  + `CLOBBER`：在儲存操作期間，清除和取代所有屬性 (包含未建模屬性)。透過刪除並重新建立項目來完成這項操作。使用版本控制的欄位限制條件也會予以忽略。

   如果您未指定映射器執行個體的儲存行為，則預設值為 `UPDATE`。
**注意**  
DynamoDBMapper 交易操作不支援 `DynamoDBMapperConfig.SaveBehavior` 列舉。
+ `DynamoDBMapperConfig.TableNameOverride` 物件：指示映射器執行個體忽略類別之 `DynamoDBTable` 註釋所指定的資料表名稱，並改為使用您提供的不同資料表名稱。在執行時期將資料分割為多個資料表時，這十分有用。

您可以視需要覆寫每個操作的 `DynamoDBMapper` 預設組態物件。

# 含版本編號的 DynamoDB 及樂觀鎖定
<a name="DynamoDBMapper.OptimisticLocking"></a>

*樂觀鎖定*是一種策略，確保您要更新 (或刪除) 的用戶端項目與 Amazon DynamoDB 中的項目相同。如果您使用此策略，則會保護其他項目的寫入不會覆寫資料庫寫入，反之亦然。

使用樂觀鎖定，每個項目都有做為版本編號的屬性。如果您從資料表中擷取項目，則應用程式會記錄該項目的版本編號。您可以更新項目，但只有在伺服器端的版本編號尚未變更時。若版本不相符，表示已有其他人在您之前進行修改。更新嘗試失敗，因為您有此項目的過期版本。如果發生這種情況，請檢索項目然後嘗試進行更新以重試一次。樂觀鎖定預防您意外覆寫其他人所作的變更。同時也預防其他人意外覆寫您所作的變更。

雖然您可以實作自己的樂觀鎖定策略，但 適用於 Java 的 AWS SDK 提供 `@DynamoDBVersionAttribute`註釋。在資料表的映射類別中，您指定一個屬性來存放版本編號，並使用此註釋進行標示。當您儲存物件時，DynamoDB 資料表中的對應項目會有屬性可存放版本編號。當您第一次儲存物件時，`DynamoDBMapper` 會指派版本編號，並在每次更新項目時自動遞增版本編號。只有在用戶端物件版本與 DynamoDB 資料表中項目的對應版本編號相符時，您的更新或刪除請求才會成功。

 如果發生下列情況，則會擲回 `ConditionalCheckFailedException`：
+  您使用含 `@DynamoDBVersionAttribute` 的樂觀鎖定，而且伺服器上的版本值與用戶端上的值不同。
+  您可以搭配使用 `DynamoDBMapper` 與 `DynamoDBSaveExpression`，以在儲存資料時指定自己的條件式限制條件，而且這些限制條件會失敗。

**注意**  
DynamoDB 全域資料表會在並行更新間使用「最後寫入者獲勝」核對機制。如果您使用的是全域資料表，最後寫入者政策獲勝。因此，在此情況下，鎖定政策不會如預期般運作。
`DynamoDBMapper` 交易寫入操作不支援同一物件的 `@DynamoDBVersionAttribute` 標註和條件表達式。如果交易寫入內的物件以 `@DynamoDBVersionAttribute` 標註，且具有條件表達式，則會拋出 SdkClientException。

例如，下列 Java 程式碼定義有數個屬性的 `CatalogItem` 類別。`Version` 屬性會標上 `@DynamoDBVersionAttribute` 註釋。

**Example**  

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

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

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

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

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

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

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

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

您可以將 `@DynamoDBVersionAttribute` 註釋套用至基本包裝函式類別所提供的可為 Null 類型，而基本包裝函式類別提供可為 Null 類型 (例如 `Long` 和 `Integer`)。

樂觀鎖定對這些 `DynamoDBMapper` 方法的影響如下：
+ `save`：針對新項目，`DynamoDBMapper` 會指派初始版本編號 1。如果您擷取項目，請更新其一或多個屬性並嘗試儲存變更，只有在用戶端的版本編號與伺服器端的相符時，儲存操作才會成功。`DynamoDBMapper` 會自動遞增版本編號。
+ `delete`：`delete` 方法會採用物件作為參數，而 `DynamoDBMapper` 會在刪除項目之前執行版本檢查。如果請求中指定 `DynamoDBMapperConfig.SaveBehavior.CLOBBER`，則可以停用版本檢查。

  `DynamoDBMapper` 內的樂觀鎖定內部實作，使用 DynamoDB 所提供的條件式更新和條件式刪除支援。
+ `transactionWrite` —
  + `Put`：針對新項目，`DynamoDBMapper` 會指派初始版本編號 1。如果您擷取項目，請更新其一或多個屬性並嘗試儲存變更，只有在用戶端的版本編號與伺服器端的相符時，Put 操作才會成功。`DynamoDBMapper` 會自動遞增版本編號。
  + `Update`：針對新項目，`DynamoDBMapper` 會指派初始版本編號 1。如果您擷取項目，請更新其一或多個屬性並嘗試儲存變更，只有在用戶端的版本編號與伺服器端的相符時，update 操作才會成功。`DynamoDBMapper` 會自動遞增版本編號。
  + `Delete`：`DynamoDBMapper` 會在刪除項目之前執行版本檢查。只有用戶端與伺服器端的版本號碼相符時，delete 操作才會成功。
  + `ConditionCheck`：不支援 `ConditionCheck` 操作的 `@DynamoDBVersionAttribute` 註釋。以 `@DynamoDBVersionAttribute` 標註 `ConditionCheck` 項目時，會拋出 SdkClientException。

## 停用樂觀鎖定
<a name="DynamoDBMapper.OptimisticLocking.Disabling"></a>

若要停用樂觀鎖定，您可以將 `DynamoDBMapperConfig.SaveBehavior` 列舉值從 `UPDATE` 變更為 `CLOBBER`。您可以建立跳過版本檢查的 `DynamoDBMapperConfig` 執行個體來執行這項操作，並將此執行個體用於所有請求。如需 `DynamoDBMapperConfig.SaveBehavior` 和其他選用 `DynamoDBMapper` 參數的資訊，請參閱「[DynamoDBMapper 的選用組態設定](DynamoDBMapper.OptionalConfig.md)」。

您也只能設定特定操作的鎖定行為。例如，下列 Java 程式碼片段使用 `DynamoDBMapper` 來儲存型錄項目。指定 `DynamoDBMapperConfig.SaveBehavior` 的方式是將選用 `DynamoDBMapperConfig` 參數新增至 `save` 方法。

**注意**  
transactionWrite 方法不支援 DynamoDBMapperConfig.SaveBehavior 組態。不支援停用 transactionWrite 的樂觀鎖定。

**Example**  

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

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

# 在 DynamoDB 中映射任意資料
<a name="DynamoDBMapper.ArbitraryDataMapping"></a>

除了支援的 Java 類型之外 (請參閱 [適用於 Java 的 DynamoDBMapper 支援的資料類型](DynamoDBMapper.DataTypes.md))，您還可以使用應用程式中未直接映射至 Amazon DynamoDB 類型的類型。若要映射這些類型，您必須提供將複雜類型轉換為 DynamoDB 支援之類型的實作 (反之亦然)，並使用 `@DynamoDBTypeConverted` 註釋來標註複雜類型存取子方法。轉換器程式碼會在儲存或載入物件時轉換資料。它也用於使用複雜類型的所有操作。請注意，在查詢和掃描操作期間比較資料時，會針對 DynamoDB 中所存放的資料進行比較。

例如，請考慮下列可定義本身為 `CatalogItem` 之 `Dimension` 屬性的 `DimensionType` 類別。此屬性會將項目維度存放為高度、寬度和厚度。假設您決定將這些項目維度存放為 DynamoDB 中的字串 (例如 8.5x11x.05)。下列範例提供轉換器程式碼，以將 `DimensionType` 物件轉換為字串以及將字串轉換為 `DimensionType`。



**注意**  
此程式碼範例假設您已根據 [在 DynamoDB 中建立資料表，以及載入程式碼範例的資料](SampleData.md) 一節的說明將資料載入 DynamoDB 的帳戶。  
如需執行下列範例的逐步說明，請參閱「[Java 程式碼範例](CodeSamples.Java.md)」。

**Example**  

```
public class DynamoDBMapperExample {

    static AmazonDynamoDB client;

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

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

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

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

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

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

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

        mapper.save(bookRetrieved);

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

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

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

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

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

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

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

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

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

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

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

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

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

    static public class DimensionType {

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

        public String getLength() {
            return length;
        }

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

        public String getHeight() {
            return height;
        }

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

        public String getThickness() {
            return thickness;
        }

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

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

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

        @Override
        public DimensionType unconvert(String s) {

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

            return itemDimension;
        }
    }
}
```

# DynamoDBMapper 範例
<a name="DynamoDBMapper.Examples"></a>

適用於 Java 的 AWS SDK 提供 `DynamoDBMapper` 類別，可讓您將用戶端類別映射至 DynamoDB 資料表。若要使用 `DynamoDBMapper`，請定義 DynamoDB 資料表中項目與程式碼中其對應物件執行個體之間的關係。`DynamoDBMapper` 類別也讓您執行各種建立、讀取、更新和對項目進行刪除 (CRUD) 操作，以及執行查詢和掃描資料表。

若要進一步了解如何使用 `DynamoDBMapper`，請參閱《*適用於 Java 1.x 的 AWS SDK 開發人員指南*》中[使用適用於 Java 的 AWS SDK 的 DynamoDB 範例](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-dynamodb.html)。

# Java 2.x：DynamoDB 增強型用戶端
<a name="DynamoDBEnhanced"></a>

DynamoDB 增強型用戶端是適用於 Java 的 AWS SDK 2 (v2) 版中的高階程式庫。提供將客戶端類別映射到 DynamoDB 資料表的直接方式。您要在自己的程式碼中定義資料表及其對應模型類別之間的關係。定義關係之後，您可以直觀地對 DynamoDB 中的資料表或項目執行各種建立、讀取、更新或刪除 (CRUD) 操作。

如需有關如何將增強型用戶端與 DynamoDB 搭配使用的詳細資訊，請參閱[適用於 Java 的 AWS SDK 2.x 中的使用 DynamoDB 增強型用戶端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)。

# 在 DynamoDB 中使用 .NET 文件模型
<a name="DotNetSDKMidLevel"></a>

適用於 .NET 的 AWS SDK 提供文件模型類別，包裝一部分低階 Amazon DynamoDB 操作，可進一步簡化您的程式碼編寫。在文件模型中，主類別為 `Table` 和 `Document`。`Table` 類別提供資料操作方法，例如 `PutItem`、`GetItem` 和 `DeleteItem`。該類別也提供 `Query` 和 `Scan` 方法。`Document` 類別則代表資料表中的單一項目。

上述文件模型類別可在 `Amazon.DynamoDBv2.DocumentModel` 命名空間中取得。

**注意**  
您無法使用文件模型建立、更新和刪除資料表。但文件模型支援大部分的常見資料操作。

**Topics**
+ [支援的資料類型](#MidLevelAPILimitations.SupportedTypes)

## 支援的資料類型
<a name="MidLevelAPILimitations.SupportedTypes"></a>

文件模型會支援一組原始的 .NET 資料類型和集合資料類型。模型目前支援下列基本資料類型。
+ `bool`
+ `byte` 
+ `char`
+ `DateTime`
+ `decimal`
+ `double`
+ `float`
+ `Guid`
+ `Int16`
+ `Int32`
+ `Int64`
+ `SByte`
+ `string`
+ `UInt16`
+ `UInt32`
+ `UInt64`

下表摘要說明上述 .NET 類型與 DynamoDB 類型的映射。


****  

| .NET 基本類型 | DynamoDB 類型 | 
| --- | --- | 
|  所有數字類型  |  `N` (數字類型)  | 
|  所有字串類型  |  `S` (字串類型)   | 
|  MemoryStream, byte[]  |  `B` (二進位類型)   | 
| bool | N (數字類型)。0 代表 false，1 代表 true。 | 
| DateTime | S (字串類型)。DateTime 值會以 ISO-8601 格式字串存放。 | 
| Guid | S (字串類型)。 | 
| 集合類型 (List、HashSet 和陣列) | BS (二進位集) 類型、SS (字串集) 類型和 NS (數字集) 類型。 | 

適用於 .NET 的 AWS SDK 會定義將 DynamoDB 的布林值、null 值、清單和映射類型映射到 .NET 文件模型 API 的類型：
+ 使用 `DynamoDBBool` 作為布林類型。
+ 使用 `DynamoDBNull` 作為 null 類型。
+ 使用 `DynamoDBList` 作為清單類型。
+ 使用 `Document` 作為映射類型。

**注意**  
支援空白的二進位值。
支援讀取空白字串值。寫入 DynamoDB 時，字串 Set 類型的屬性值會支援空白字串的屬性值。List 或 Map 類型中包含的字串類型的空白字串屬性值和空白字串值會從寫入請求中捨棄

# 使用 .NET 物件持久性模型和 DynamoDB
<a name="DotNetSDKHighLevel"></a>

 適用於 .NET 的 AWS SDK 提供物件持久性模型，可讓您將用戶端類別映射至 Amazon DynamoDB 資料表。然後每個物件執行個體會映射至相對應資料表中的某個項目。為了將用戶端物件儲存至資料表，物件持久性模型會提供 `DynamoDBContext` 類別 (即 DynamoDB 的進入點)。此類別可讓您連線至 DynamoDB，繼而存取資料表、執行各種 CRUD 操作以及執行查詢。

物件持久性模型提供了一組屬性，可將用戶端類別映射到資料表，並將屬性/欄位映射至資料表屬性。

**注意**  
物件持久性模型不提供用於建立、更新或刪除資料表的 API。它只提供資料操作。您只能使用 適用於 .NET 的 AWS SDK 低階 API 來建立、更新和刪除資料表。

以下範例會示範物件持久性模型的運作方式。它會從 `ProductCatalog` 資料表開始作業。它將 `Id` 作為主索引鍵。

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

假設您的 `Book` 類別具有 `Title`、`ISBN` 以及 `Authors` 屬性。您可以透過新增物件持久性模型所定義的屬性，將 `Book` 類別映射至 `ProductCatalog` 資料表中，如下列 C\$1 程式碼範例所示。

**Example**  

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

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

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

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

在上述範例中，`DynamoDBTable` 屬性會將 `Book` 類別映射至 `ProductCatalog` 資料表。

物件持久性模型支援類別屬性與資料表屬性之間的明確映射和預設映射。
+ **明確映射：**若要將屬性映射至主索引鍵，您必須使用 `DynamoDBHashKey` 和 `DynamoDBRangeKey` 物件持久性模型屬性。此外，對於非主索引鍵屬性，如果類別中的屬性名稱和要對應的資料表屬性不相同，則必須明確新增 `DynamoDBProperty` 屬性來定義映射。

  在上述範例中，`Id` 屬性會映射至具有相同名稱的主索引鍵，`BookAuthors` 屬性則會映射至 `ProductCatalog` 資料表中的 `Authors` 屬性。
+ **預設映射：**依預設，物件持久性模型會將類別屬性映射至資料表中具有相同名稱的屬性。

  在上述範例中，屬性 `Title` 和 `ISBN` 會映射至 `ProductCatalog` 資料表中具有相同名稱的屬性。

您不必映射每個類別屬性。您可以新增 `DynamoDBIgnore` 屬性來識別這些屬性。當您將 `Book` 執行個體儲存至資料表時，`DynamoDBContext` 不會包含 `CoverPage` 屬性。在擷取書籍執行個體時，它也不會傳回此屬性。

您可以映射 .NET 基本類型的屬性，如 int 和字串。只要提供適當的轉換器將任意資料映射至其中一種 DynamoDB 類型，您也可以映射任意資料類型。若要進一步了解如何映射任意類型，請參閱 [使用 適用於 .NET 的 AWS SDK 物件持久性模型使用 DynamoDB 映射任意資料](DynamoDBContext.ArbitraryDataMapping.md)。

物件持久性模型支援樂觀鎖定。在更新操作期間，這可確保您擁有即將更新項目的最新副本。如需詳細資訊，請參閱[使用 DynamoDB 和 適用於 .NET 的 AWS SDK 物件持久性模型的樂觀鎖定](DynamoDBContext.VersionSupport.md)。

如需詳細資訊，請參閱下列主題。

**Topics**
+ [支援的資料類型](#DotNetDynamoDBContext.SupportedTypes)
+ [.NET 物件持久性模型的 DynamoDB 屬性](DeclarativeTagsList.md)
+ [.NET 物件持久性模型的 DynamoDBContext 類別](DotNetDynamoDBContext.md)
+ [使用 DynamoDB 和 適用於 .NET 的 AWS SDK 物件持久性模型的樂觀鎖定](DynamoDBContext.VersionSupport.md)
+ [使用 適用於 .NET 的 AWS SDK 物件持久性模型使用 DynamoDB 映射任意資料](DynamoDBContext.ArbitraryDataMapping.md)

## 支援的資料類型
<a name="DotNetDynamoDBContext.SupportedTypes"></a>

物件持久性模型會支援一組基本的 .NET 資料類型、集合和任意資料類型。模型目前支援下列基本資料類型。
+ `bool`
+ `byte` 
+ `char`
+ `DateTime`
+ `decimal`
+ `double`
+ `float`
+ `Int16`
+ `Int32`
+ `Int64`
+ `SByte`
+ `string`
+ `UInt16`
+ `UInt32`
+ `UInt64`

物件持久性模型也支援 .NET 集合類型。`DynamoDBContext` 能夠轉換具體的集合類型和簡單的純舊 CLR 物件 (POCO)。

下表摘要說明上述 .NET 類型與 DynamoDB 類型的映射。


****  

| .NET 基本類型 | DynamoDB 類型 | 
| --- | --- | 
|  所有數字類型  |  `N` (數字類型)  | 
|  所有字串類型  |  `S` (字串類型)   | 
|  MemoryStream, byte[]  |  `B` (二進位類型)   | 
| bool | N (數字類型)。0 代表 false，1 代表 true。 | 
| 集合類型 | BS (二進位集) 類型、SS (字串集) 類型和 NS (數字集) 類型。 | 
| DateTime | S (字串類型)。DateTime 值會以 ISO-8601 格式字串存放。 | 

物件持久性模型也支援任意資料類型。不過，您必須提供轉換器程式碼，才能將複雜類型映射至 DynamoDB 類型。

**注意**  
支援空白的二進位值。
支援讀取空白字串值。寫入 DynamoDB 時，字串 Set 類型的屬性值會支援空白字串的屬性值。List 或 Map 類型中包含的字串類型的空白字串屬性值和空白字串值會從寫入請求中捨棄

# .NET 物件持久性模型的 DynamoDB 屬性
<a name="DeclarativeTagsList"></a>

本節說明物件持久性模型所提供的屬性，讓您可以將類別和屬性映射至 DynamoDB 資料表和屬性。

**注意**  
在下列屬性中，只有 `DynamoDBTable` 和 `DynamoDBHashKey` 是必要屬性。

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

將類別屬性映射至全域次要索引的分割區索引鍵。如果您需要對全域次要索引進行 `Query`，請使用此屬性。

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

將類別屬性映射至全域次要索引的排序索引鍵。如果您需要對全域次要索引進行 `Query`，並且想要使用索引的排序索引鍵來縮小您結果的範圍，請使用此屬性。

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

將類別屬性映射至資料表主索引鍵的分割區索引鍵。主索引鍵屬性不能是集合類型。

下列 C\$1 程式碼範例會映射 `Book` 類別至 `ProductCatalog` 資料表，並映射 `Id` 屬性至資料表主索引鍵的分割區索引鍵。

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

    // Additional properties go here.
}
```

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

指出應該忽略的相關聯屬性。如果您不想儲存任何類別屬性，可以新增此屬性來指示 `DynamoDBContext` 將物件儲存到資料表時不包含此屬性。

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

將類別屬性映射至本機次要索引的排序索引鍵。如果您需要對本機次要索引進行 `Query`，並且想要使用索引的排序索引鍵來縮小您結果的範圍，請使用此屬性。

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

將類別屬性映射至資料表屬性。如果類別屬性映射至具有相同名稱的資料表屬性，則不需要指定此屬性。不過，如果名稱不同，您可以使用此標籤提供映射。在下列 C\$1 陳述式中，`DynamoDBProperty` 會將 `BookAuthors` 屬性映射至資料表中的 `Authors` 屬性。

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

當儲存物件資料至相應的資料表時，`DynamoDBContext` 會使用此映射資訊來建立 `Authors` 屬性。

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

指定類別屬性的替代名稱。如果您正在撰寫自訂轉換器，以將任意資料映射至 DynamoDB 資料表 (其中類別屬性的名稱與資料表屬性不同)，則此功能非常有用。

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

將類別屬性映射至資料表主索引鍵的排序索引鍵。如果資料表具有複合主鍵 (分割區索引鍵和排序索引鍵)，則必須在類別映射中同時指定 `DynamoDBHashKey` 和 `DynamoDBRangeKey` 屬性。

例如，範例資料表 `Reply` 有一個由 `Id` 分割區索引鍵和 `Replenishment` 排序索引鍵組成的主索引鍵。下列 C\$1 程式碼範例將 `Reply` 類別映射至 `Reply` 資料表。類別定義也會指出其中兩個屬性映射至主索引鍵。

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

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

識別 DynamoDB 中類別要映射的目標資料表。例如，下列 C\$1 程式碼範例將 `Developer` 類別映射至 DynamoDB 中的 `People` 資料表。

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

此屬性可被繼承或覆寫。
+ `DynamoDBTable` 屬性可被繼承。在上述範例中，如果新增新從 `Developer` 類別繼承的新類別 `Lead`，它也會映射至 `People` 資料表。`Developer` 和 `Lead` 物件都存放在 `People` 資料表中。
+ `DynamoDBTable` 屬性也可被寫。在下列 C\$1 程式碼範例中，`Manager` 類別繼承自 `Developer` 類別。但是，明確新增 `DynamoDBTable` 屬性會將類別映射到另一個資料表 (`Managers`)。

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

 您可以新增選用參數 `LowerCamelCaseProperties`，以便請求 DynamoDB 在儲存物件至資料表時，將屬性名稱的第一個字母變成小寫，如下列 C\$1 範例所示。

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

在儲存 `Developer` 類別的執行個體時，`DynamoDBContext` 會儲存 `DeveloperName` 屬性作為 `developerName`。

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

標識用於儲存項目版本編號的類別屬性。如需版本控制的詳細資訊，請參閱「[使用 DynamoDB 和 適用於 .NET 的 AWS SDK 物件持久性模型的樂觀鎖定](DynamoDBContext.VersionSupport.md)」。

# .NET 物件持久性模型的 DynamoDBContext 類別
<a name="DotNetDynamoDBContext"></a>

`DynamoDBContext` 類別是 Amazon DynamoDB 資料庫的進入點。它可讓您連線至 DynamoDB，繼而存取各種資料表中的資料、執行各種 CRUD 操作以及執行查詢。此 `DynamoDBContext` 類別提供下列方法。

**Topics**
+ [Create​MultiTable​BatchGet](#w2aac17b9c21c23c39b7)
+ [Create​MultiTable​BatchWrite](#w2aac17b9c21c23c39b9)
+ [CreateBatchGet](#w2aac17b9c21c23c39c11)
+ [CreateBatchWrite](#w2aac17b9c21c23c39c13)
+ [刪除](#w2aac17b9c21c23c39c15)
+ [Dispose](#w2aac17b9c21c23c39c17)
+ [Execute​Batch​Get](#w2aac17b9c21c23c39c19)
+ [Execute​Batch​Write](#w2aac17b9c21c23c39c21)
+ [FromDocument](#w2aac17b9c21c23c39c23)
+ [FromQuery](#w2aac17b9c21c23c39c25)
+ [FromScan](#w2aac17b9c21c23c39c27)
+ [Get​Target​Table](#w2aac17b9c21c23c39c29)
+ [Load](#w2aac17b9c21c23c39c31)
+ [Query](#w2aac17b9c21c23c39c33)
+ [Save](#w2aac17b9c21c23c39c35)
+ [Scan](#w2aac17b9c21c23c39c37)
+ [ToDocument](#w2aac17b9c21c23c39c39)
+ [指定 DynamoDBContext 的選用參數](#OptionalConfigParams)

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

建立由多個個別 `BatchGet` 物件組成的 `MultiTableBatchGet` 物件。其中的每個 `BatchGet` 物件都可用來從單一 DynamoDB 資料表中擷取項目。

若要從資料表擷取項目，請使用 `ExecuteBatchGet` 方法，將 `MultiTableBatchGet` 物件作為參數傳遞。

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

建立由多個個別 `BatchWrite` 物件組成的 `MultiTableBatchWrite` 物件。其中的每個 `BatchWrite` 物件可用來寫入或刪除單一 DynamoDB 資料表中的項目。

若要寫入資料表，請使用 `ExecuteBatchWrite` 方法，將 `MultiTableBatchWrite` 物件作為參數傳遞。

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

建立 `BatchGet` 物件，您可以使用該物件從資料表中擷取多個項目。

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

建立 `BatchWrite` 物件，您可以使用該物件將多個項目放入資料表中，或從資料表中刪除多個項目。

## 刪除
<a name="w2aac17b9c21c23c39c15"></a>

刪除資料表中的項目。這個方法需要您希望刪除之項目的主索引鍵。您可以提供主索引鍵值或包含主索引鍵值的用戶端物件，作為此方法的參數。
+ 如果指定用戶端物件作為參數，且已啟用樂觀鎖定，則只有在物件的用戶端和伺服器端版本相符時，才能成功刪除項目。
+ 如果只指定主索引鍵值作為參數，無論您是否已啟用樂觀鎖定，刪除都會成功。

**注意**  
若要在背景執行此操作，請改用 `DeleteAsync` 方法。

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

處置所有受管和非受管的資源。

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

從一或多個資料表讀取資料，處理 `MultiTableBatchGet` 中的所有 `BatchGet` 物件。

**注意**  
若要在背景執行此操作，請改用 `ExecuteBatchGetAsync` 方法。

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

在一或多個資料表中寫入或刪除資料，處理 `MultiTableBatchWrite` 中的所有 `BatchWrite` 物件。

**注意**  
若要在背景執行此操作，請改用 `ExecuteBatchWriteAsync` 方法。

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

若為 `Document` 執行個體，`FromDocument` 方法會傳回用戶端類別的執行個體。

如果您想使用文件模型類別以及物件持久性模型來執行任何資料操作，這會很有幫助。如需 提供之文件模型類別的詳細資訊 適用於 .NET 的 AWS SDK，請參閱 [在 DynamoDB 中使用 .NET 文件模型](DotNetSDKMidLevel.md)。

假設您有名為 `doc` 的 `Document` 物件，且其中包含 `Forum` 項目的表示法。(若要查看如何建構此物件，請參閱本主題後續內容中的 `ToDocument` 方法說明。) 您可以使用 `FromDocument` 從 `Document` 擷取 `Forum` 項目，如下列 C\$1 程式碼範例所示。

**Example**  

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

**注意**  
如果您的 `Document` 物件會實作 `IEnumerable` 介面，您可以使用 `FromDocuments` 方法。這允許您逐一查看 `Document` 中的所有類別執行個體。

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

以 `QueryOperationConfig` 物件中定義的查詢參數執行 `Query` 操作。

**注意**  
若要在背景執行此操作，請改用 `FromQueryAsync` 方法。

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

以 `ScanOperationConfig` 物件中定義的掃描參數執行 `Scan` 操作。

**注意**  
若要在背景執行此操作，請改用 `FromScanAsync` 方法。

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

擷取指定類型的目標資料表。如果您正在撰寫自訂轉換器，將任意資料映射至 DynamoDB 資料表，而且需要判斷哪個資料表與自訂資料類型相關聯，則此功能非常有用。

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

從資料表擷取項目。這個方法只需要您希望擷取之項目的主索引鍵。

DynamoDB 預設會傳回數值最終一致的項目。如需最終一致性模式的資訊，請參閱 [DynamoDB 讀取一致性](HowItWorks.ReadConsistency.md)。

`Load` 或 `LoadAsync` 方法會呼叫 [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) 操作，這需要您指定資料表的主索引鍵。由於 `GetItem` 會忽略 `IndexName` 參數，您無法使用索引分割區或排序索引鍵載入項目。因此您必須使用資料表主索引鍵來載入項目。

**注意**  
若要在背景執行此操作，請改用 `LoadAsync` 方法。若要檢視使用 `LoadAsync` 方法在 DynamoDB 資料表執行高階 CRUD 操作的範例，請參閱下列範例。

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

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

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

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

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

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

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

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

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

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

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

根據您提供的查詢參數查詢資料表。

您只能查詢具有複合主鍵 (分割區索引鍵和排序索引鍵) 的資料表。查詢時，必須指定分割區索引鍵和套用至排序索引鍵的條件。

假設您有用戶端 `Reply` 類別映射至 DynamoDB 中的 `Reply` 資料表。下列 C\$1 程式碼範例會查詢 `Reply` 資料表，找出過去 15 天所張貼的論壇主題回覆。`Reply` 資料表的主索引鍵具有 `Id` 分割區索引鍵和 `ReplyDateTime` 排序索引鍵。

**Example**  

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

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

這會傳回 `Reply` 物件的集合。

`Query` 方法會傳回「延遲載入」`IEnumerable` 集合。它一開始只會傳回一頁的結果，然後視需要進行服務呼叫來取得下一頁。若要取得所有相符的項目，您只需要逐一查看 `IEnumerable`。

如果資料表具有簡易主索引鍵 (分割區索引鍵)，您便不能使用 `Query` 方法。不過，您可以使用 `Load` 方法並提供分割區索引鍵來擷取項目。

**注意**  
若要在背景執行此操作，請改用 `QueryAsync` 方法。

## Save
<a name="w2aac17b9c21c23c39c35"></a>

將指定的物件儲存至資料表。如果輸入物件中指定的主索引鍵不存在於資料表中，該方法會將新項目新增至資料表中。如果主索引鍵存在，該方法會更新現有項目。

如果您已設定樂觀鎖定，則只有在用戶端和項目的伺服器端版本相符時才能成功更新項目。如需詳細資訊，請參閱[使用 DynamoDB 和 適用於 .NET 的 AWS SDK 物件持久性模型的樂觀鎖定](DynamoDBContext.VersionSupport.md)。

**注意**  
若要在背景執行此操作，請改用 `SaveAsync` 方法。

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

執行整個資料表掃描。

您可以指定掃描條件來篩選掃描結果。您可以根據資料表中的任何屬性來評估條件。假設您有用戶端 `Book` 類別映射至 DynamoDB 中的 `ProductCatalog` 資料表。下列 C\$1 範例會掃描資料表，並且只會傳回價格低於 0 的所有書籍項目。

**Example**  

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

`Scan` 方法會傳回「延遲載入」`IEnumerable` 集合。它一開始只會傳回一頁的結果，然後視需要進行服務呼叫來取得下一頁。若要取得所有相符的項目，您只需要逐一查看 `IEnumerable`。

出於效能考量，您應查詢資料表並避免執行資料表掃描。

**注意**  
若要在背景執行此操作，請改用 `ScanAsync` 方法。

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

從類別執行個體傳回 `Document` 文件模型類別的執行個體。

如果您想使用文件模型類別以及物件持久性模型來執行任何資料操作，這會很有幫助。如需 提供之文件模型類別的詳細資訊 適用於 .NET 的 AWS SDK，請參閱 [在 DynamoDB 中使用 .NET 文件模型](DotNetSDKMidLevel.md)。

假設您有用戶端類別映射至範例 `Forum` 資料表。然後，您可以使用 `DynamoDBContext` 從 `Forum` 資料表中獲取項目作為 `Document` 物件，如下列 C\$1 程式碼範例所示。

**Example**  

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

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

## 指定 DynamoDBContext 的選用參數
<a name="OptionalConfigParams"></a>

使用物件持久性模型時，您可以指定 `DynamoDBContext` 的下列選用參數。
+ **`ConsistentRead`：**當使用 `Load`、`Query` 或 `Scan` 操作來擷取資料時，您可以新增此選用參數來請求資料的最新數值。
+ **`IgnoreNullValues`：**此參數會通知 `DynamoDBContext` 在 `Save` 操作期間忽略屬性上的 Null 數值。如果此參數為 false (或未設定)，則會將 Null 數值轉譯為刪除特定屬性的指令。
+ **`SkipVersionCheck`：**此參數會通知 `DynamoDBContext` 不要在儲存或刪除項目時比較版本。如需版本控制的詳細資訊，請參閱「[使用 DynamoDB 和 適用於 .NET 的 AWS SDK 物件持久性模型的樂觀鎖定](DynamoDBContext.VersionSupport.md)」。
+ **`TableNamePrefix`：**使用特定字串作為所有資料表名稱的字首。如果此參數為 null (或未設定)，則不會使用字首。
+ `DynamoDBEntryConversion` – 指定用戶端使用的轉換結構描述。您可以將此參數設定為版本 V1 或 V2。V1 是預設版本。

  根據您設定的版本，此參數的行為會變更。例如：
  + 在 V1 中，`bool` 資料類型會轉換為 `N` 數字類型，其中 0 代表 false，1 代表 true。在 V2 中，`bool` 會轉換為 `BOOL`。
  + 在 V2 中，清單和陣列不會與 HashSet 一起分組。數值、字串類型和二進位類型的清單和陣列會轉換為 `L` (清單) 類型，可以傳送空白清單來更新清單。這與 V1 不同，其中空白清單不會透過線路傳送。

    在 V1 中，清單、HashSet 和陣列等集合類型都視為相同。清單、HashSet 和數值陣列會轉換為 `NS` (數字集) 類型。

  下列範例會將轉換結構描述版本設定為 V2，變更 .NET 類型和 DynamoDB 資料類型之間的轉換行為。

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

下列 C\$1 範例會指定 `ConsistentRead` 和 `SkipVersionCheck` 這兩個上述選用參數來建立新的 `DynamoDBContext`。

**Example**  

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

`DynamoDBContext` 包含這些選用參數，以及您使用此內容傳送的每個請求。

您可以使用 `DynamoDBContext` 為個別操作指定參數，而不是在 `DynamoDBContext` 層級設定這些參數，如下列 C\$1 程式碼範例所示。此範例會載入特定的書籍項目。`DynamoDBContext` 的 `Load` 方法會指定 `ConsistentRead` 和 `SkipVersionCheck` 等選用參數。

**Example**  

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

在此例中，`DynamoDBContext` 只有在傳送 `Get` 請求時才會包含這些參數。

# 使用 DynamoDB 和 適用於 .NET 的 AWS SDK 物件持久性模型的樂觀鎖定
<a name="DynamoDBContext.VersionSupport"></a>

物件持久性模型中的樂觀鎖定支援可確保應用程式的項目版本與伺服器端的項目版本相同，然後再更新或刪除項目。假設您要擷取待更新的項目。不過，在您傳回更新之前，某些其他應用程式會更新相同的項目。現在應用程式的項目有過時的副本。如果沒有樂觀鎖定，您執行的任何更新都會覆寫其他應用程式所做的更新。

物件持久性模型的樂觀鎖定功能提供了 `DynamoDBVersion` 標籤，可讓您用來啟用樂觀鎖定。若要使用此功能，請在類別中新增一項屬性，以便儲存版本編號。您可以將 `DynamoDBVersion` 屬性加入該屬性。當您第一次儲存物件時，`DynamoDBContext` 會指派版本編號，並在每次更新項目時遞增值。

只有在用戶端物件版本與伺服器端項目的對應版本編號相符時，您的更新或刪除請求才會成功。如果應用程式有過時的副本，它必須先從伺服器取得最新版本，才能更新或刪除該項目。

下列 C\$1 程式碼範例會定義 `Book` 類別，該類別具有將其映射至 `ProductCatalog` 資料表的物件持久性屬性。類別中的 `VersionNumber` 屬性裝飾了會儲存版本編號數值的 `DynamoDBVersion` 屬性。

**Example**  

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

**注意**  
您只可將 `DynamoDBVersion` 屬性套用至可為 null 的數字基本類型 (如 `int?`)。

樂觀鎖定對 `DynamoDBContext` 操作的影響如下：
+ 對於新項目，`DynamoDBContext` 會指派初始版本編號 0。如果您擷取現有項目，請更新其一或多個屬性並嘗試儲存變更，只有在用戶端的版本編號與伺服器端的相符時，儲存操作才會成功。`DynamoDBContext` 會遞增版本號碼。您不需要設定版本編號。
+ `Delete` 方法提供可將主索引鍵值或物件作為參數的多載，如下列 C\$1 程式碼範例所示。  
**Example**  

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

  如果提供物件作為參數，則只有在物件版本符合對應的伺服器端項目版本時才能成功刪除。不過，如果提供主索引鍵值作為參數，`DynamoDBContext` 不知道任何版本編號，其會在沒有檢查是哪個版本的情況下刪除項目。

  請注意，物件持久性模型程式碼中的樂觀鎖定內部實作會使用 DynamoDB 中的條件式更新和條件式刪除 API 動作。

## 停用樂觀鎖定
<a name="DotNetDynamoDBContext.DisablingOptimisticLocking"></a>

若要停用樂觀鎖定，您可以使用 `SkipVersionCheck` 組態屬性。您可以在建立 `DynamoDBContext` 時設定此屬性。在這種情況下，您使用內容發起的任何請求都會停用樂觀鎖定。如需詳細資訊，請參閱[指定 DynamoDBContext 的選用參數](DotNetDynamoDBContext.md#OptionalConfigParams)。

您可以停用特定操作的樂觀鎖定，而不是在內容層級設定屬性，如下列 C\$1 程式碼範例所示。此範例會使用內容來刪除書籍項目。`Delete` 方法可設定選用 `SkipVersionCheck` 屬性為 true，停用版本檢查。

**Example**  

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

# 使用 適用於 .NET 的 AWS SDK 物件持久性模型使用 DynamoDB 映射任意資料
<a name="DynamoDBContext.ArbitraryDataMapping"></a>

除了支援的 .NET 類型之外 (請參閱 [支援的資料類型](DotNetSDKHighLevel.md#DotNetDynamoDBContext.SupportedTypes))，您還可以使用應用程式中未直接映射至 Amazon DynamoDB 類型的類型。只要您提供轉換器將資料從任意類型轉換為 DynamoDB 類型，物件持久性模型就支援儲存任意類型的資料，反之亦然。轉換器程式碼會在物件的儲存和載入期間轉換資料。

您可以在用戶端建立任何類型。不過，存放在資料表中的資料是 DynamoDB 類型之一；在查詢和掃描期間，所做的任何資料比較都會與存放在 DynamoDB 中的資料進行比較。

下列 C\$1 程式碼範例會定義具有 `Id`、`Title`、`ISBN` 以及 `Dimension` 屬性的 `Book` 類別。`Dimension` 屬性具有 `DimensionType`，可說明 `Height`、`Width` 和 `Thickness` 屬性。範例程式碼提供了轉換器方法 `ToEntry` 和 `FromEntry` 來轉換 `DimensionType` 與 DynamoDB 字串類型之間的資料。例如，在儲存 `Book` 執行個體時，轉換器會建立一個書籍 `Dimension` 字串，例如 "8.5x11x.05"。在擷取書籍時，它會將字串轉換為 `DimensionType` 執行個體。

此範例會將 `Book` 類型映射為 `ProductCatalog` 資料表。它儲存了一個範例 `Book` 執行個體、擷取、更新其維度並再次儲存更新的 `Book`。



如需測試下列範例的逐步說明，請參閱 [.NET 程式碼範例](CodeSamples.DotNet.md)。

**Example**  

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

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

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

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

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

                context.Save(myBook);

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

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

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

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

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

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

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

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

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

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

# 執行此開發人員指南中的程式碼範例
<a name="CodeSamples"></a>

 AWS SDKs 以下列語言為 Amazon DynamoDB 提供廣泛的支援：
+ [Java](https://aws.amazon.com/sdk-for-java)
+ [瀏覽器中的 JavaScript](https://aws.amazon.com/sdk-for-browser)
+ [.NET](https://aws.amazon.com/sdk-for-net)
+ [Node.js](https://aws.amazon.com/sdk-for-node-js)
+ [PHP](https://aws.amazon.com/sdk-for-php)
+ [Python](https://aws.amazon.com/sdk-for-python)
+ [Ruby](https://aws.amazon.com/sdk-for-ruby)
+ [C\$1\$1](https://aws.amazon.com/sdk-for-cpp)
+ [Go](https://aws.amazon.com/sdk-for-go)
+ [Android](https://aws.amazon.com/mobile/sdk/)
+ [iOS](https://aws.amazon.com/mobile/sdk/)

此開發人員指南中的程式碼範例使用下列程式設計語言，提供 DynamoDB 操作的更深入說明：
+ [Java 程式碼範例](CodeSamples.Java.md)
+ [.NET 程式碼範例](CodeSamples.DotNet.md)

在開始此練習之前，您需要建立 AWS 帳戶、取得存取金鑰和私密金鑰，並在電腦上設定 AWS Command Line Interface (AWS CLI)。如需詳細資訊，請參閱[設定 DynamoDB (Web 服務)](SettingUp.DynamoWebService.md)。

**注意**  
如果您使用可下載的 DynamoDB 版本，則需要使用 AWS CLI 來建立資料表和範例資料。您也需要使用每個 AWS CLI 命令指定 `--endpoint-url` 參數。如需詳細資訊，請參閱[設定區域端點](DynamoDBLocal.UsageNotes.md#DynamoDBLocal.Endpoint)。

# 在 DynamoDB 中建立資料表，以及載入程式碼範例的資料
<a name="SampleData"></a>

如需在 DynamoDB 中建立資料表、在範例資料集中載入、查詢資料以及更新資料的基礎知識，請參閱下文。
+ [步驟 1：在 DynamoDB 建立資料表](getting-started-step-1.md)
+ [步驟 2：將資料寫入 DynamoDB 資料表](getting-started-step-2.md)
+ [步驟 3：從 DynamoDB 資料表讀取資料](getting-started-step-3.md)
+ [步驟 4：更新 DynamoDB 資料表中的資料](getting-started-step-4.md)

# Java 程式碼範例
<a name="CodeSamples.Java"></a>

**Topics**
+ [Java：設定您的 AWS 登入資料](#CodeSamples.Java.Credentials)
+ [Java：設定 AWS 區域和端點](#CodeSamples.Java.RegionAndEndpoint)

此開發人員指南包含 Java 程式碼片段及可立即執行的程式。您可以在以下章節中找到這些程式碼範例：
+ [在 DynamoDB 使用項目和屬性](WorkingWithItems.md)
+ [在 DynamoDB 中使用資料表和資料](WorkingWithTables.md)
+ [在 DynamoDB 中查詢資料表](Query.md)
+ [掃描 DynamoDB 中的資料表](Scan.md)
+ [在 DynamoDB 中使用次要索引來改善資料存取](SecondaryIndexes.md)
+ [Java 1.x：DynamoDBMapper](DynamoDBMapper.md)
+ [DynamoDB Streams 的變更資料擷取](Streams.md)

您可以搭配使用 [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/) 與 Eclipse 來快速開始使用。除了功能完整的 IDE 之外，您還可以取得 適用於 Java 的 AWS SDK 具有自動更新的 ，以及用於建置 AWS 應用程式的預先設定範本。

**執行 Java 程式碼範例 (使用 Eclipse)**

1. 下載並安裝 [Eclipse](http://www.eclipse.org) IDE。

1. 下載並安裝 [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/)。

1. 啟動 Eclipse，然後在 **Eclipse** 選單上，選擇 **File (檔案)**、**New (新建)**，再選擇 **Other (其他)**。

1. 在 **Select a wizard** (選取協助程式) 中，選擇 **AWS**，選擇 **AWS Java Project** (AWS Java 專案)，再選擇 **Next** (下一步)。

1. 在**建立 AWS Java 中**，執行下列動作：

   1. 在**專案名稱** 中，輸入您的專案名稱。

   1. 在 **Select Account (選取帳戶)** 中，從清單選擇您的憑證描述檔。

      如果這是您第一次使用 [AWS Toolkit for Eclipse](https://aws.amazon.com/eclipse/)，請選擇**設定 AWS 帳戶**來設定您的 AWS 登入資料。

1. 選擇 **Finish (完成)** 建立專案。

1. 從 **Eclipse** 選單，選擇 **File (檔案)**、**New (新建)**，再選擇 **Class (類別)**。

1. 在 **Java Class (Java 類別)** 的 **Name (名稱)** 中，輸入您的類別名稱 (使用與您要執行之程式碼範例相同的名稱)，然後選擇 **Finish (完成)** 建立類別。

1. 將程式碼範例從文件頁面複製到 Eclipse 編輯器。

1. 若要執行程式碼，請在 Eclipse 選單上選擇 **Run (執行)**。

Java 軟體開發套件提供可與 DynamoDB 搭配使用的安全執行緒用戶端。根據最佳實務，您的應用程式應該建立一個用戶端，並在執行緒之間重複使用該用戶端。

如需更多資訊，請參閱[適用於 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java)。

**注意**  
此指南中的程式碼範例適用於最新版的 適用於 Java 的 AWS SDK。  
如果您使用的是 AWS Toolkit for Eclipse，則可以為適用於 Java 的 SDK 設定自動更新。若要在 Eclipse 中執行此作業，請前往 **Preferences** (偏好設定)，然後依次選擇 **AWS 工具組**、**適用於 Java 的 AWS SDK**、**Download new SDK automatically** (自動下載新的開發套件)。

## Java：設定您的 AWS 登入資料
<a name="CodeSamples.Java.Credentials"></a>

適用於 Java 的 SDK 需要您在執行時間提供 AWS 登入資料給應用程式。本指南中的程式碼範例假設您使用的是 AWS 登入資料檔案，如 *適用於 Java 的 AWS SDK 開發人員指南*中的[設定 AWS 登入資料](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/set-up-creds.html)中所述。

以下是名為 的 AWS 登入資料檔案範例`~/.aws/credentials`，其中波狀符號字元 (`~`) 代表您的主目錄。

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

## Java：設定 AWS 區域和端點
<a name="CodeSamples.Java.RegionAndEndpoint"></a>

依預設，程式碼範例會存取美國西部 (奧勒岡) 區域的 DynamoDB。您可以修改 `AmazonDynamoDB` 屬性來變更區域。

以下程式碼範例會執行個體化新的 `AmazonDynamoDB`。

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

您可以使用 `withRegion` 方法，對任何可用區域中的 DynamoDB 執行程式碼。如需完整清單，請參閱 *Amazon Web Services 一般參考* 中的 [AWS 區域與端點](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region)。

如果您想要使用 DynamoDB 在電腦本機執行程式碼範例，請設定端點如下：

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

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

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

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

# .NET 程式碼範例
<a name="CodeSamples.DotNet"></a>

**Topics**
+ [.NET：設定您的 AWS 登入資料](#CodeSamples.DotNet.Credentials)
+ [.NET：設定 AWS 區域和端點](#CodeSamples.DotNet.RegionAndEndpoint)

此指南包含 .NET 程式碼片段與可立即執行的程式。您可以在以下章節中找到這些程式碼範例：
+ [在 DynamoDB 使用項目和屬性](WorkingWithItems.md)
+ [在 DynamoDB 中使用資料表和資料](WorkingWithTables.md)
+ [在 DynamoDB 中查詢資料表](Query.md)
+ [掃描 DynamoDB 中的資料表](Scan.md)
+ [在 DynamoDB 中使用次要索引來改善資料存取](SecondaryIndexes.md)
+ [在 DynamoDB 中使用 .NET 文件模型](DotNetSDKMidLevel.md)
+ [使用 .NET 物件持久性模型和 DynamoDB](DotNetSDKHighLevel.md)
+ [DynamoDB Streams 的變更資料擷取](Streams.md)

您可以將 適用於 .NET 的 AWS SDK 與 Toolkit for Visual Studio 搭配使用，以快速開始使用。

**執行 .NET 程式碼範例 (使用 Visual Studio)**

1. 下載並安裝 [Microsoft Visual Studio](https://www.visualstudio.com)。

1. （選用） 下載並安裝 [Toolkit for Visual Studio](https://aws.amazon.com/visualstudio/)。

1. 設定您的 AWS 登入資料。在共用登入資料檔案 () 中設定 AWS 登入資料設定檔`~/.aws/credentials`。如需詳細資訊，請參閱《適用於 .NET 的 AWS SDK 開發人員指南》**中的[設定 AWS 憑證](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html)。

1. 啟動 Visual Studio。選擇 **File (檔案)**、**New (新增)**、**Project (專案)**。

1. 搜尋**主控台應用程式**，選取以 .NET 為目標的 C\$1 範本，然後選擇**下一步**。設定您的專案名稱和位置，然後選擇**建立**。

1. 將適用於 DynamoDB NuGet 的 AWS SDK 套件新增至您的專案：

   1. 在方案總管中，開啟您專案的內容 (右鍵) 選單，然後選擇 **Manage NuGet Packages (管理 NuGet 套件)**。

   1. 在 NuGet 套件管理員中，選擇 **Browse (瀏覽)**。

   1. 在搜尋方塊中輸入 **AWSSDK.DynamoDBv2**，並等候搜尋完成。

   1. 選擇 **AWSSDK.DynamoDBv2**，然後選擇 **Install (安裝)**。

1. 在您的 Visual Studio 專案中，開啟 `Program.cs`。將內容取代為您要執行的文件頁面中的程式碼範例。

1. 若要執行程式碼，請在 Visual Studio 工具列中選擇 **Start (啟動)**。

 適用於 .NET 的 SDK 提供使用 DynamoDB 的安全執行緒用戶端。根據最佳實務，您的應用程式應該建立一個用戶端，並在執行緒之間重複使用該用戶端。

如需詳細資訊，請參閱[適用於 .NET 的AWS 軟體開發套件](https://aws.amazon.com/sdk-for-net)。

**注意**  
此指南中的程式碼範例適用於最新版的 適用於 .NET 的 AWS SDK。

## .NET：設定您的 AWS 登入資料
<a name="CodeSamples.DotNet.Credentials"></a>

 適用於 .NET 的 SDK 需要您在執行時間提供 AWS 登入資料給應用程式。本指南中的程式碼範例假設您使用 SDK 存放區來管理 AWS 登入資料檔案，如《 *適用於 .NET 的 AWS SDK 開發人員指南*》中的[使用 SDK 存放區](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#sdk-store)中所述。

Toolkit for Visual Studio 支援來自任意數目帳戶的多組憑證。每個集合都稱為*描述檔*。Visual Studio 會將項目新增至專案的 `App.config` 檔案，讓您的應用程式可以在執行時間找到 AWS 登入資料。

下列範例顯示預設 `App.config` 檔案，當您使用 Toolkit for Visual Studio 建立新的專案時，就會生成此檔案。

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

在執行時間，程式會使用 `AWSProfileName` 項目指定的`default`一組 AWS 登入資料。 AWS 登入資料本身會以加密形式保存在 SDK 存放區中。Toolkit for Visual Studio 提供圖形化使用者介面來管理所有來自於 Visual Studio 的憑證。如需詳細資訊，請參閱《AWS Toolkit for Visual Studio 使用者指南》中的[指定憑證](https://docs.aws.amazon.com/AWSToolkitVS/latest/UserGuide/tkv_setup.html#creds)。

**注意**  
依預設，程式碼範例會存取美國西部 (奧勒岡) 區域的 DynamoDB。您可以修改 App.config 檔案中的 `AWSRegion` 項目來變更區域。您可以將 `AWSRegion` 設定為 DynamoDB 可用的任何區域。如需完整清單，請參閱 *Amazon Web Services 一般參考* 中的 [AWS 區域與端點](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region)。

## .NET：設定 AWS 區域和端點
<a name="CodeSamples.DotNet.RegionAndEndpoint"></a>

依預設，程式碼範例會存取美國西部 (奧勒岡) 區域的 DynamoDB。您可以修改 `App.config` 檔案中的 `AWSRegion` 項目來變更區域。或者，您亦可以修改 `AmazonDynamoDBClient` 屬性來變更區域。

以下程式碼範例會執行個體化新的 `AmazonDynamoDBClient`。這會修改用戶端，讓程式碼對不同區域中的 DynamoDB 執行。

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

如需區域的完整清單，請參閱 *Amazon Web Services 一般參考* 中的 [AWS 區域與端點](https://docs.aws.amazon.com/general/latest/gr/rande.html#ddb_region)。

如果您想要使用 DynamoDB 在電腦本機執行程式碼範例，請設定端點如下：

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

# DynamoDB 低階 API
<a name="Programming.LowLevelAPI"></a>

Amazon DynamoDB *低階 API* 為 DynamoDB 的協定層級介面。在此層級中，每個 HTTP(S) 要求都必須依照正確的格式，並附上有效的數位簽章。

 AWS SDKs 會代表您建構低階 DynamoDB API 請求，並處理來自 DynamoDB 的回應。您如此即可專注於應用程式的邏輯，而非低階的結節。但您仍可從了解低階 DynamoDB API 運作方式的基本知識中獲益。

如需低階 DynamoDB API 的詳細資訊，請參閱《[Amazon DynamoDB API 參考](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/)》。

**注意**  
DynamoDB Streams 有自己的低階 API，與 DynamoDB 的低階 API 不同，且完全由 AWS SDKs 支援。  
如需詳細資訊，請參閱[DynamoDB Streams 的變更資料擷取](Streams.md)。如需低階 DynamoDB Streams API，請參閱《[Amazon DynamoDB Streams API 參考](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Operations_Amazon_DynamoDB_Streams.html)》。

低階 DynamoDB API 使用 JavaScript 物件表示法 (JSON) 作為接線協定格式。JSON 以階層顯示資料，以便同時傳達資料值和資料結構。名稱/值對以 `name:value` 格式定義。資料階層由成對的巢狀括住之名稱與值加以定義。

DynamoDB 只會使用 JSON 作為傳輸協定，而非儲存格式。 AWS SDKs 使用 JSON 將資料傳送至 DynamoDB，而 DynamoDB 會以 JSON 回應。DynamoDB 不會以 JSON 格式永久存放資料。

**注意**  
如需 JSON 的詳細資訊，請參閱 `JSON.org` 網站上的 [JSON 簡介](http://json.org)。

**Topics**
+ [要求格式](#Programming.LowLevelAPI.RequestFormat)
+ [回應格式](#Programming.LowLevelAPI.ResponseFormat)
+ [資料類型描述項](#Programming.LowLevelAPI.DataTypeDescriptors)
+ [數值資料](#Programming.LowLevelAPI.Numbers)
+ [二進位資料](#Programming.LowLevelAPI.Binary)

![\[DynamoDB 低階 API 和 AWS SDKs處理通訊協定層級請求和回應的方式。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/SDKSupport.DDBLowLevelAPI.png)


## 要求格式
<a name="Programming.LowLevelAPI.RequestFormat"></a>

DynamoDB 低階 API 接受 HTTP(S) `POST` 請求作為輸入。 AWS 軟體開發套件會為您建構這些請求。

假設您有一個名為 `Pets` 的資料表，其索引鍵結構描述由 `AnimalType` (分割區索引鍵) 及 `Name` (排序索引鍵) 所組成。這些屬性的類型皆為 `string`。若要從 擷取項目`Pets`，軟體 AWS 開發套件會建構下列請求。

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

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

請注意以下此要求的相關事宜：
+ `Authorization` 標頭包含 DynamoDB 驗證請求所需之資訊。如需詳細資訊，請參閱 中的[簽署 AWS API 請求](https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html)和[簽署第 4 版簽署程序](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)*Amazon Web Services 一般參考*。
+ `X-Amz-Target` 標頭包含 DynamoDB 操作的名稱：`GetItem`。(此也會同時附上低階 API 版本，在此案例中為 `20120810`。)
+ 要求的承載 (主體) 包含操作的參數 (JSON 格式)。若是 `GetItem` 操作，參數為 `TableName` 與 `Key`。

## 回應格式
<a name="Programming.LowLevelAPI.ResponseFormat"></a>

收到請求時，DynamoDB 會處理該請求並會傳回回應。針對前述的要求，HTTP(S) 回應承載會包含操作的結果，如下列範例中所示。

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

此時， AWS 軟體開發套件會將回應資料傳回至您的應用程式，以供進一步處理。

**注意**  
若 DynamoDB 無法處理請求，其會傳回 HTTP 錯誤碼及訊息。 AWS 軟體開發套件會以例外狀況的形式，將這些傳播到您的應用程式。如需詳細資訊，請參閱[使用 DynamoDB 時發生錯誤](Programming.Errors.md)。

## 資料類型描述項
<a name="Programming.LowLevelAPI.DataTypeDescriptors"></a>

低階 DynamoDB API 協定需要每個屬性都要附有一個資料類型的描述項。*資料類型描述項*是告知 DynamoDB 如何解譯每項屬性的字符。

「[要求格式](#Programming.LowLevelAPI.RequestFormat)」與「[回應格式](#Programming.LowLevelAPI.ResponseFormat)」中的範例，展示如何使用資料類型描述項的範例。`GetItem` 要求指定 `Pets` 索引鍵結構描述屬性 (`AnimalType` 與 `Name`) 為 `S`，即類型為 `string`。`GetItem` 回應包含具有 `string` (`S`)、`number` (`N`)、`map` (`M`) 以及 `list` (`L`) 類型屬性的 *Pets* 項目。

下列為 DynamoDB 資料類型描述項的完整清單：
+ **`S`**：字串
+ **`N`**：數字
+ **`B`**：二進位
+ **`BOOL`**：布林值
+ **`NULL`**：Null
+ **`M`**：映射
+ **`L`**：清單
+ **`SS`**：字串集合
+ **`NS`**：數字集合
+ **`BS`**：二進位集合

下表顯示每個資料類型描述項的正確 JSON 格式。請注意，數字會以字串表示以保留精確度，而布林值和 null 則使用其原生 JSON 類型。


| 描述項 | JSON format (JSON 格式) | 備註 | 
| --- | --- | --- | 
| S | \$1"S": "Hello"\$1 | 值是 JSON 字串。 | 
| N | \$1"N": "123.45"\$1 | 值是字串，而不是 JSON 號碼。這可保留跨語言的精確度。 | 
| B | \$1"B": "dGhpcyBpcyBhIHRlc3Q="\$1 | 值是 base64 編碼字串。 | 
| BOOL | \$1"BOOL": true\$1 | 值是 JSON 布林值 (true 或 false)，而不是字串。 | 
| NULL | \$1"NULL": true\$1 | 值是true表示 null 的 JSON 布林值。 | 
| M | \$1"M": \$1"Name": \$1"S": "Joe"\$1\$1\$1 | 值是屬性名稱值對的 JSON 物件。 | 
| L | \$1"L": [\$1"S": "Red"\$1, \$1"N": "5"\$1]\$1 | 值是屬性值的 JSON 陣列。 | 
| SS | \$1"SS": ["Red", "Blue"]\$1 | 值是字串的 JSON 陣列。 | 
| NS | \$1"NS": ["1", "2.5"]\$1 | 值是數字字串的 JSON 陣列。 | 
| BS | \$1"BS": ["U3Vubnk=", "UmFpbnk="]\$1 | 值是 base64 編碼字串的 JSON 陣列。 | 

**注意**  
 如需 DynamoDB 資料類型的詳細說明，請參閱 [資料類型](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes)。

## 數值資料
<a name="Programming.LowLevelAPI.Numbers"></a>

不同的程式語言提供不同程度的 JSON 支援。在某些情況下，您可能會決定要使用第三方的程式庫進行 JSON 文件之驗證及剖析。

某些第三方程式庫會依據 JSON 數字類型建置，提供其本身的類型，例如 `int`、`long` 或 `double`。但 DynamoDB 中的原生數字資料類型，無法精確地映射到這些其他資料類型，所以這些類型的差異可能會導致衝突。此外，許多 JSON 程式庫不會處理固定精確度的數值，而是會自動針對包含小數點的數字，推斷為雙精確度資料類型。

為解決這些問題，DynamoDB 提供了不會造成資料遺失的單一數字類型。為避免不必要的隱含轉換為雙精確度值，DynamoDB 使用字串來進行數值資料傳輸。此方法提供了更新屬性值的彈性，同時還能維持適當的排序語意，例如將值 "01"、"2" 及 "03" 依適當的順序排列。

若數字精確度對您的應用程式來說很重要，則應在將其傳遞至 DynamoDB 之前，先將數值轉換為字串。

## 二進位資料
<a name="Programming.LowLevelAPI.Binary"></a>

DynamoDB 支援二進制屬性。但 JSON 原本並不支援二進位資料的編碼。若要在要求中傳送二進位資料，您必須將其編碼為 Base64 格式。在接收到請求時，DynamoDB 會將 Base64 資料解碼回二進位。

DynamoDB 使用的 base64 編碼結構描述會在 Internet Engineering Task Force (IETF) 網站上的 [RFC 4648](http://tools.ietf.org/html/rfc4648) 說明。

# 使用 Python 和 Boto3 為 Amazon DynamoDB 編寫程式
<a name="programming-with-python"></a>

本指南為想要透過 Python 使用 Amazon DynamoDB 的程式設計人員提供指導。了解不同的抽象層、組態管理、錯誤處理、控制重試政策、管理保持連線等。

**Topics**
+ [關於 Boto](#programming-with-python-about)
+ [使用 Boto 文件](#programming-with-python-documentation)
+ [了解用戶端和資源抽象層](#programming-with-python-client-resource)
+ [使用資料表資源 batch\$1writer](#programming-with-python-batch-writer)
+ [探索用戶端和資源層的其他程式碼範例](#programming-with-python-additional-code)
+ [了解用戶端和資源物件如何與工作階段和執行緒互動](#programming-with-python-sessions-thread-safety)
+ [自訂 Config 物件](#programming-with-python-config)
+ [錯誤處理](#programming-with-python-error-handling)
+ [日誌](#programming-with-python-logging)
+ [事件勾點](#programming-with-python-event-hooks)
+ [分頁和分頁程式](#programming-with-python-pagination)
+ [等待程式](#programming-with-python-waiters)

## 關於 Boto
<a name="programming-with-python-about"></a>

您可以使用適用於 Python 的官方 AWS SDK 從 Python 存取 DynamoDB，通常稱為 **Boto3**。Boto (發音為 boh-toh) 的名稱來自亞馬遜河原生的淡水海豚。Boto3 程式庫是程式庫的第三個主要版本，於 2015 年首次發行。Boto3 程式庫相當大，因為它支援所有 AWS 服務，而不只是 DynamoDB。此指導僅針對 Boto3 中與 DynamoDB 相關的部分。

Boto 由 維護並發佈 AWS 為 GitHub 上託管的開放原始碼專案。分為兩個套件：[Botocore](https://github.com/boto/botocore) 和 [Boto3](https://github.com/boto/boto3)。
+ **Botocore** 提供低階功能。在 Botocore 中，您會找到用戶端、工作階段、憑證、組態和例外類別。
+ **Boto3** 建置在 Botocore 之上，提供更高階、更具 Python 風格的介面。具體而言，它公開 DynamoDB 資料表做為資源，並提供比服務導向的低階用戶端介面更簡單、更優雅的介面。

由於這些專案託管在 GitHub 上，因此您可以檢視原始程式碼、追蹤未解決的問題，或提交您自己的問題。

## 使用 Boto 文件
<a name="programming-with-python-documentation"></a>

使用下列資源開始使用 Boto 文件：
+ 從 [Quickstart 區段](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)開始，該區段提供安裝套件的堅實起點。如需安裝 Boto3 的說明，請前往此處 (Boto3 通常可在 等 AWS 服務內自動使用 AWS Lambda)。
+ 之後，請專注於文件的 [DynamoDB 指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/dynamodb.html)。它說明如何執行基本的 DynamoDB 活動：建立和刪除資料表、操作項目，以及執行批次操作、查詢和掃描。其範例使用**資源**介面。當您看到 `boto3.resource('dynamodb')`，表示您正在使用較高階的**資源**介面。
+ 在本指南之後，您可以檢閱 [DynamoDB 參考](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html)。此登陸頁面提供您可使用的類別和方法的完整清單。在頂端，您會看到 `DynamoDB.Client` 類別，提供所有控制平面和資料平面操作的低階存取。在底部則可查看 `DynamoDB.ServiceResource` 類別，這是更高階且具有 Python 風格的介面。您可以使用它來建立資料表、跨資料表執行批次操作，或取得資料表特定動作的 `DynamoDB.ServiceResource.Table` 執行個體。

## 了解用戶端和資源抽象層
<a name="programming-with-python-client-resource"></a>

您將使用的兩個介面是**用戶端**介面和資源****介面。
+ 低階**用戶端**介面提供對基礎服務 API 的 1 對 1 映射。DynamoDB 提供的每個 API 都可以透過用戶端取得。這表示用戶端介面可以提供完整的功能，但使用起來通常更冗長且複雜。
+ 較高階的**資源**介面不提供基礎服務 API 的 1 對 1 映射。不過，它提供可讓您更方便存取服務的方法，例如 `batch_writer`。

以下是使用用戶端介面插入項目的範例。請注意所有的值如何以映射形式傳遞，其中鍵代表其類型 (字串為「S」，數字為「N」)，值則為字串。這稱為 DynamoDB JSON 格式。

```
import boto3

dynamodb = boto3.client('dynamodb')

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

以下是使用資源介面的相同 `PutItem` 操作。資料類型是隱含的：

```
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('YourTableName')

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

如有需要，您可以使用 boto3 提供的 `TypeSerializer` 和 `TypeDeserializer` 類別，在一般 JSON 和 DynamoDB JSON 之間轉換：

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

以下是如何使用用戶端介面執行查詢。它將查詢表達為 JSON 建構，使用需要變數替換的 `KeyConditionExpression` 字串來處理任何潛在的關鍵字衝突：

```
import boto3

client = boto3.client('dynamodb')

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

使用資源介面的相同查詢操作可以縮短和簡化：

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

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

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

最後，假設您想要取得資料表的大致大小 (這是保留在資料表上的中繼資料，大約每 6 小時更新一次)。使用用戶端介面，您可以執行 `describe_table()` 操作，並從傳回的 JSON 結構提取答案：

```
import boto3

dynamodb = boto3.client('dynamodb')

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

透過資源介面，資料表會隱含地執行描述操作，並直接將資料顯示為屬性：

```
import boto3

dynamodb = boto3.resource('dynamodb')

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

**注意**  
考慮使用用戶端或資源界面進行開發時，請注意，根據[資源文件](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html)，不會將新功能新增至資源界面：「 AWS Python SDK 團隊不打算將新功能新增至 boto3 中的資源界面。在 boto3 的生命週期期間，現有的介面將繼續運作。客戶可以透過用戶端介面尋找存取較新服務功能。」

## 使用資料表資源 batch\$1writer
<a name="programming-with-python-batch-writer"></a>

`batch_writer` 是一種便利的方法，僅適用於較高階的資料表資源。DynamoDB 支援批次寫入操作，在一個網路請求中最多允許 25 個放置或刪除操作。像這樣的批次處理可最大限度減少網路往返，從而提高效率。

透過低階用戶端程式庫，您可以使用 `client.batch_write_item()` 操作來執行批次。您必須手動將工作分成 25 個批次。在每次操作之後，您也必須請求獲得未處理項目的清單 (有些寫入操作可能會成功，有些則可能會失敗)。然後，您必須將這些未處理的項目再次傳遞至稍後的 `batch_write_item()` 操作。有大量的樣板程式碼。

[Table.batch\$1writer](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/batch_writer.html) 方法會建立內容管理員，用於以批次方式寫入物件。它會顯示一個介面，看起來像是您一次寫入一個項目，但其實在內部會分批緩衝和傳送項目。它也會隱含地處理未處理的項目重試。

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

table = dynamodb.Table('YourTableName')

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

## 探索用戶端和資源層的其他程式碼範例
<a name="programming-with-python-additional-code"></a>

您也可以參考下列程式碼範例儲存庫，以探索在使用用戶端和資源的情況下，各種函數的使用方式：
+ [官方 AWS 單一動作程式碼範例。](https://docs.aws.amazon.com/code-library/latest/ug/python_3_dynamodb_code_examples.html)
+ [官方 AWS 案例導向程式碼範例。](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python)
+ [社群維護的單一動作程式碼範例。](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/python)

## 了解用戶端和資源物件如何與工作階段和執行緒互動
<a name="programming-with-python-sessions-thread-safety"></a>

資源物件不具備執行緒安全性，不應跨執行緒或程序共用。如需詳細資訊，請參閱[資源指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html#multithreading-or-multiprocessing-with-resources)。

相反地，用戶端物件通常具備執行緒安全性，但特定進階功能除外。如需更多詳細資訊，請參閱[用戶端指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html#multithreading-or-multiprocessing-with-clients)。

工作階段物件不具備執行緒安全性。因此，每次在多執行緒環境中建立用戶端或資源時，應先建立新的工作階段，然後從工作階段建立用戶端或資源。如需詳細資訊，請參閱[工作階段指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/session.html#multithreading-or-multiprocessing-with-sessions)。

當您呼叫 `boto3.resource()` 時，您會隱含地使用預設工作階段。這有助於撰寫單執行緒程式碼。撰寫多執行緒程式碼時，您會想要先為每個執行緒建構新的工作階段，然後從該工作階段擷取資源：

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

## 自訂 Config 物件
<a name="programming-with-python-config"></a>

建構用戶端或資源物件時，您可以傳遞選用的已命名參數來自訂行為。名為 `config` 的參數會解鎖各種功能。這是 `botocore.client.Config` 的執行個體，而 [Config 參考文件](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html)會顯示它公開供您控制的所有內容。[組態指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html)提供良好的概觀。

**注意**  
您可以修改在工作階段層級、 AWS 組態檔案內或作為環境變數的許多行為設定。

**逾時的組態**

自訂組態的一個用途是調整聯網行為：
+ **connect\$1timeout (浮點數或整數)** – 嘗試建立連線時擲出逾時例外狀況的秒數。預設值為 60 秒。
+ **read\$1timeout (浮點數或整數)** – 嘗試從連線讀取時擲出逾時例外狀況前的秒數。預設值為 60 秒。

對 DynamoDB 而言，60 秒的逾時太長了。這表示暫時性網路故障會導致用戶端延遲一分鐘，然後才可以再試一次。下列程式碼會將逾時縮短為一秒：

```
import boto3
from botocore.config import Config

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

如需逾時的更多討論，請參閱[調整延遲感知 DynamoDB 應用程式的 AWS Java SDK HTTP 請求設定](https://aws.amazon.com/blogs/database/tuning-aws-java-sdk-http-request-settings-for-latency-aware-amazon-dynamodb-applications/)。請注意，Java SDK 具有比 Python 更多的逾時組態。

**保持連線的組態**

如果您使用的是 botocore 1.27.84 或更新版本，您也可以控制 **TCP Keep-Alive**：
+ **tcp\$1keepalive** (bool) - 啟用 TCP Keep-Alive 通訊端選項，如果設定為 `True` (預設為 `False`)，則在建立新連線時使用。從 botocore 1.27.84 開始才能使用。

將 TCP Keep-Alive 設定為 `True` 可減少平均延遲。以下是當您有正確的 botocore 版本時，將 TCP Keep-Alive 設定為 true 的範例程式碼：

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

required_version = "1.27.84"
current_version = botocore.__version__

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

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

**注意**  
TCP Keep-Alive 與 HTTP Keep-Alive 不同。使用 TCP Keep-Alive 時，基礎作業系統會透過通訊端連線傳送小型封包，以保持連線並立即偵測任何下降。使用 HTTP Keep-Alive 時，會重複使用基礎通訊端上建置的 Web 連線。boto3 一律會啟用 HTTP Keep-Alive。

閒置連線可以保持運作的時間有限制。如果您有閒置連線，但希望下一個請求使用已建立的連線，請考慮定期傳送請求 (每分鐘傳送一次)。

**重試的組態**

組態也會接受稱為**重試**的字典，您可以在其中指定所需的重試行為。當 SDK 收到錯誤且錯誤為暫時性類型時，會在 SDK 中重試。如果在內部重試錯誤 (重試最終產生成功的回應)，從呼叫程式碼的角度就不會看到錯誤，只是延遲稍微增加。以下是您可以指定的值：
+ **max\$1attempts** – 一個整數，表示對單一請求進行的重試嘗試次數上限。例如，若將此值設定為 2，初始請求後最多可重試請求兩次。若將此值設為 0，則在初始請求後不會嘗試任何重試。
+ **total\$1max\$1attempts** – 一個整數，代表對單一請求所嘗試的總數上限。這包括初始請求，因此值 1 表示不會重試任何請求。如果同時提供 `total_max_attempts` 和 `max_attempts`，則 `total_max_attempts` 具有優先權。`total_max_attempts` 優先於 `max_attempts`，因為它映射到 `AWS_MAX_ATTEMPTS` 環境變數和 `max_attempts` 組態檔案值。
+ **mode** – 一個字串，代表應該使用的重試模式 botocore 類型。有效的值如下：
  + **legacy** – 預設模式。第一次重試等待 50 毫秒，然後使用基本係數為 2 的指數退避。對於 DynamoDB，會執行最多總計 10 次嘗試 (除非以上述覆寫)。
**注意**  
使用指數退避時，最後一次嘗試將等待近 13 秒。
  + **標準** – 具名標準，因為它更符合其他 AWS SDKs。第一次重試將等待從 0 毫秒到 1,000 毫秒的隨機時間。如果需要再次重試，會挑選從 0 毫秒到 1,000 毫秒的另一個隨機時間，並乘以 2。如果需要額外的重試，會執行相同的隨機挑選乘以 4，依此類推。每次等待上限為 20 秒。相較於 `legacy` 模式，此模式在偵測到更多失敗條件時會執行重試。對於 DynamoDB，會執行最多總共 3 次嘗試 (除非以上述覆寫)。
  + **adaptive** - 實驗性重試模式，包含標準模式的所有功能，但新增了自動用戶端限流。透過自適應速率限制，SDKs可以降低傳送請求的速率，以更好地適應 AWS 服務的容量。這是一種暫時性模式，其行為可能會變更。

您可以在[重試指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html)中找到這些重試模式的擴展定義，也可以在 [SDK 參考的重試行為主題](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html)中找到。

以下是明確使用 `legacy` 重試政策的範例，總共最多 3 個請求 (2 次重試)：

```
import boto3
from botocore.config import Config

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

由於 DynamoDB 是高度可用、低延遲的系統，因此建議您可以比內建重試政策所允許的程度，加快重試速度。您可以實作自己的重試政策，方法是將最大嘗試次數設定為 0，自行擷取例外狀況，並從自己的程式碼適當重試，而不是依賴 boto3 進行隱含重試。

如果您管理自己的重試政策，您會想要區分限流和錯誤：
+ **限流** (由 `ProvisionedThroughputExceededException` 或 `ThrottlingException` 表示) 表示運作狀態良好的服務，通知您已超過 DynamoDB 資料表或分割區的讀取或寫入容量。每經過一毫秒，就能獲得更多的讀取或寫入容量，因此您可以快速重試 (例如每 50 毫秒) 以嘗試存取該新發布的容量。使用限流時，您不需要特別使用指數退避，因為傳回限流對 DynamoDB 很輕量，而且不會向您收取每次請求的費用。指數退避會將較長的延遲指派給已等待最長時間的用戶端執行緒，以統計方式將 p50 和 p99 向外延伸。
+ **錯誤** (由 `InternalServerError` 或 `ServiceUnavailable` 等表示) 表示服務有暫時性問題。可能涉及整個資料表，也可能只是您正在讀取或寫入的分割區。發生錯誤時，您可以在重試之前暫停更長的時間 (例如 250 毫秒或 500 毫秒)，並使用抖動來交錯重試。

**集區連線上限的組態**

最後，組態可讓您控制連線集區大小：
+ **max\$1pool\$1connections (整數)** – 在連線集區中保留的最大連線數。如果未指定任何值，則會使用預設值 10。

此選項控制要保留在集區中以供重複使用的 HTTP 連線數目上限。每個工作階段會保留不同的集區。如果您預期針對同一工作階段建置的用戶端或資源有 10 個以上的執行緒，您應該考慮將此值提高，讓執行緒不必等待其他正在使用集區連線的執行緒。

```
import boto3
from botocore.config import Config

my_config = Config(
   max_pool_connections = 20
)

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

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

## 錯誤處理
<a name="programming-with-python-error-handling"></a>

AWS Boto3 中並未靜態定義所有 服務例外狀況。這是因為 AWS 服務的錯誤和例外狀況差異很大，可能會有所變更。Boto3 將所有服務例外狀況包裝為 `ClientError`，並以結構化 JSON 公開詳細資訊。例如，錯誤回應的結構如下所示：

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

下列程式碼會擷取任何 `ClientError` 例外狀況，並查看 `Error` 內的 `Code` 字串值，以決定要採取的動作：

```
import botocore
import boto3

dynamodb = boto3.client('dynamodb')

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

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

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

部分 (但並非全部) 例外狀況代碼已具體化為最高階類別。您可以選擇直接處理這些例外狀況。使用用戶端介面時，這些例外狀況會在您的用戶端上動態填入，而您使用用戶端執行個體來擷取這些例外狀況，如下所示：

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

使用資源介面時，您必須使用 `.meta.client` 從資源周遊到基礎用戶端來存取例外狀況，如下所示：

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

若要檢閱具體化例外狀況類型的清單，您可以動態產生清單：

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

使用條件表達式執行寫入操作時，您可以請求假如表達式失敗，應在錯誤回應中傳回項目的值。

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

如需進一步了解錯誤處理和例外狀況：
+ [有關錯誤處理的 boto3 指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/error-handling.html)提供了有關錯誤處理技巧的詳細資訊。
+ [程式設計錯誤的 DynamoDB 開發人員指南區段](Programming.Errors.md)列出了您可能會遇到的錯誤。
+ [API 參考中的常見錯誤區段](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/CommonErrors.html)。
+ 每個 API 操作的文件會列出呼叫可能產生的錯誤 (例如 [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html))。

## 日誌
<a name="programming-with-python-logging"></a>

boto3 程式庫與 Python 的內建記錄模組整合，以追蹤工作階段期間發生的情況。若要控制記錄層級，您可以設定記錄模組：

```
import logging

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

這樣會設定根記錄器來記錄 `INFO` 和更高層級的訊息。系統會忽略嚴重程度低於層級的記錄訊息。記錄層級包括 `DEBUG`、`INFO`、`WARNING`、`ERROR` 和 `CRITICAL`。預設值為 `WARNING`。

boto3 中的記錄器是階層式的。程式庫使用幾個不同的記錄器，每個記錄器對應至程式庫的不同部分。您可以個別控制每個記錄器的行為：
+ **boto3**：boto3 模組的主要記錄器。
+ **botocore**：botocore 套件的主要記錄器。
+ **botocore.auth**：用於記錄請求的 AWS 簽章建立。
+ **botocore.credentials**：用於記錄憑證擷取和重新整理的程序。
+ **botocore.endpoint**：用於在透過網路傳送請求之前記錄建立請求。
+ **botocore.hooks**：用於記錄程式庫中觸發的事件。
+ **botocore.loaders**：用於載入部分 AWS 服務模型時的記錄。
+ **botocore.parsers**：用於在剖析之前記錄 AWS 服務回應。
+ **botocore.retryhandler**：用於記錄 AWS 服務請求重試的處理 （舊版）。
+ **botocore.retries.standard**：用於記錄 AWS 服務請求重試的處理 （標準或適應模式）。
+ **botocore.utils**：用於記錄程式庫中的其他活動。
+ **botocore.waiter**：用於記錄等待程式的功能，在達到特定狀態之前輪詢 AWS 服務。

其他程式庫也會記錄。在內部，boto3 會使用第三方 urllib3 來處理 HTTP 連線。當延遲很重要時，您可以監看其日誌，以確保您的集區在 urllib3 建立新連線或關閉閒置連線時獲得充分利用。
+ **urllib3.connectionpool：**用於記錄連線集區處理事件。

下列程式碼片段將大部分記錄設定為 `INFO`，`DEBUG` 記錄則用於端點和連線集區活動：

```
import logging

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

## 事件勾點
<a name="programming-with-python-event-hooks"></a>

Botocore 在執行的各個階段期間發出事件。您可以為這些事件註冊處理常式，以便每次發出事件時，都會呼叫您的處理常式。這可讓您擴充 botocore 的行為，而不必修改其內部。

例如，假設您希望每次在應用程式中對任何 DynamoDB 資料表呼叫 `PutItem` 操作時加以記錄。您可以在 `'provide-client-params.dynamodb.PutItem'` 事件上註冊，以便每次在關聯的工作階段上調用 `PutItem` 操作時擷取和記錄。範例如下：

```
import boto3
import botocore
import logging

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

logging.basicConfig(level=logging.INFO)

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

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

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

在處理常式中，您甚至可以透過程式設計方式操作參數來變更行為：

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

如需事件的詳細資訊，請參閱[事件的 botocore 文件](https://botocore.amazonaws.com/v1/documentation/api/latest/topics/events.html)和[事件的 boto3 文件](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/events.html)。

## 分頁和分頁程式
<a name="programming-with-python-pagination"></a>

有些請求，例如查詢和掃描，會限制單一請求上傳回的資料大小，並要求您重複提出請求以提取後續分頁。

您可以使用 `limit` 參數控制每個分頁要讀取的項目數量上限。例如，如果您想要最後 10 個項目，您可以使用 `limit` 僅擷取最後 10 個項目。請注意，限制是指套用任何篩選之前，應該從資料表讀取多少。篩選後無法指定您想要的確切 10 個項目；您只能控制預先篩選的計數，並在實際擷取 10 個項目時在用戶端檢查。無論限制為何，每個回應的大小上限一律為 1 MB。

如果回應包含 `LastEvaluatedKey`，則表示回應因為達到計數或大小限制而結束。索引鍵是針對回應評估的最後一個鍵。您可以擷取此 `LastEvaluatedKey` 並將其傳遞至後續呼叫做為 `ExclusiveStartKey`，以讀取該起點的下一個區塊。沒有 `LastEvaluatedKey` 傳回該項目時，表示沒有更多符合查詢或掃描的項目。

以下是一個簡單的範例 (使用資源介面，但用戶端介面具有相同的模式)，每個頁面和迴圈最多讀取 100 個項目，直到所有項目都已讀取為止。

```
import boto3

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

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

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

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

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

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

為了方便起見，boto3 可以使用分頁程式為您執行此操作。不過，它僅適用於用戶端介面。以下是改寫為使用分頁程式的程式碼：

```
import boto3

dynamodb = boto3.client('dynamodb')

paginator = dynamodb.get_paginator('query')

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

page_iterator = paginator.paginate(**query_params)

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

如需詳細資訊，請參閱[分頁程式指南](https://botocore.amazonaws.com/v1/documentation/api/latest/topics/events.html)和 [DynamoDB.Paginator.Query 的 API 參考](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/paginator/Query.html)。

**注意**  
分頁程式也有自己的組態設定，名為 `MaxItems`、`StartingToken` 和 `PageSize`。若要使用 DynamoDB 進行分頁，您應該忽略這些設定。

## 等待程式
<a name="programming-with-python-waiters"></a>

等待程式提供在繼續之前等待某些項目完成的能力。目前，僅支援等待建立或刪除資料表。在背景中，等待程式操作會每 20 秒為您檢查一次，最多 25 次。您可以自行執行此操作，但在撰寫自動化時，使用等待程式是一種簡練的方式。

此程式碼說明如何等待特定資料表建立完成：

```
# Create a table, wait until it exists, and print its ARN
response = client.create_table(...)
waiter = client.get_waiter('table_exists')
waiter.wait(TableName='YourTableName')
print('Table created:', response['TableDescription']['TableArn']
```

如需詳細資訊，請參閱[等待程式指南](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html#waiters)和[等待程式參考](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#waiters)。

# 使用 JavaScript 編寫 Amazon DynamoDB 程式
<a name="programming-with-javascript"></a>

本指南為想要搭配 JavaScript 使用 Amazon DynamoDB 的程式設計人員提供指導。了解 適用於 JavaScript 的 AWS SDK、可用的抽象層、設定連線、處理錯誤、定義重試政策、管理保持連線等。

**Topics**
+ [關於 適用於 JavaScript 的 AWS SDK](#programming-with-javascript-about)
+ [使用 適用於 JavaScript 的 AWS SDK V3](#programming-with-javascript-using-the-sdk)
+ [存取 JavaScript 文件](#programming-with-javascript-documentation)
+ [抽象層](#programming-with-javascript-abstraction-layers)
+ [使用 marshall 公用程式函數](#programming-with-javascript-using-marshall-utility)
+ [讀取項目](#programming-with-javascript-reading-items)
+ [條件式寫入](#programming-with-javascript-conditional-writes)
+ [分頁](#programming-with-javascript-pagination)
+ [指定組態](#programming-with-javascript-config)
+ [等待程式](#programming-with-javascript-waiters)
+ [錯誤處理](#programming-with-javascript-error-handling)
+ [日誌](#programming-with-javascript-logging)
+ [考量事項](#programming-with-javascript-considerations)

## 關於 適用於 JavaScript 的 AWS SDK
<a name="programming-with-javascript-about"></a>

 適用於 JavaScript 的 AWS SDK 可讓您 AWS 服務 使用瀏覽器指令碼或 Node.js 存取 。本文件著重於最新版本的 SDK (V3)。V3 適用於 JavaScript 的 AWS SDK 由 維護 AWS 為 [ GitHub 上託管的開放原始碼專案](https://github.com/aws/aws-sdk-js-v3)。問題和功能請求是公開的，您可以在 GitHub 儲存庫的問題頁面上存取它們。

JavaScript V2 類似於 V3，但包含語法差異。V3 更模組化，可更輕鬆地提供較小的相依性，並具有一級 TypeScript 支援。我們建議您使用最新版的 SDK。

## 使用 適用於 JavaScript 的 AWS SDK V3
<a name="programming-with-javascript-using-the-sdk"></a>

您可以使用 Node Package Manager 將 SDK 新增至 Node.js 應用程式。以下範例示範如何新增最常用於 DynamoDB 的 SDK 套件。
+ `npm install @aws-sdk/client-dynamodb`
+ `npm install @aws-sdk/lib-dynamodb`
+ `npm install @aws-sdk/util-dynamodb`

安裝套件會將參考新增至 package.json 專案檔案的相依性區段。您可以選擇使用較新的 ECMAScript 模組語法。如需這兩種方法的進一步詳細資訊，請參閱考量一節。

## 存取 JavaScript 文件
<a name="programming-with-javascript-documentation"></a>

使用下列資源開始使用 JavaScript 文件：
+ 存取[開發人員指南](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html)以取得核心 JavaScript 文件。安裝指示位於**設定**區段。
+ 存取 [API 參考](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/introduction/)文件，以探索所有可用的類別和方法。
+ 適用於 JavaScript 的 SDK 支援 DynamoDB AWS 服務 以外的許多 。使用下列程序來尋找 DynamoDB 的特定 API 涵蓋範圍：

  1. 從**服務**中，選擇 **DynamoDB 和程式庫**。這會記錄低階用戶端。

  1. 選擇 **lib-dynamodb**。這會記錄高階用戶端。兩個用戶端代表您可以選擇使用的兩個不同的抽象層。如需抽象層的詳細資訊，請參閱以下章節。

## 抽象層
<a name="programming-with-javascript-abstraction-layers"></a>

適用於 JavaScript V3 的 SDK 具有低階用戶端 (`DynamoDBClient`) 和高階用戶端 (`DynamoDBDocumentClient`)。

**Topics**
+ [低階客戶端 (`DynamoDBClient`)](#programming-with-javascript-low-level-client)
+ [高階用戶端 (`DynamoDBDocumentClient`)](#programming-with-javascript-high-level-client)

### 低階客戶端 (`DynamoDBClient`)
<a name="programming-with-javascript-low-level-client"></a>

低階用戶端對於基礎線路通訊協定不提供額外的抽象概念。它可讓您完全控制通訊的各個層面，但由於沒有抽象概念，因此您必須使用 DynamoDB JSON 格式執行提供項目定義等操作。

如以下範例所示，使用此格式的資料類型必須明確陳述。*S* 表示字串值，*N* 表示數值。線路上的數字一律會以標記為數字類型的字串傳送，以確保精確度不會遺失。低階 API 呼叫的命名模式例如 `PutItemCommand` 和 `GetItemCommand`。

下列範例使用低階用戶端，搭配利用 DynamoDB JSON 定義的 `Item`：

```
const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

async function addProduct() {
  const params = {
    TableName: "products",
    Item: {
      "id": { S: "Product01" },
      "description": { S: "Hiking Boots" },
      "category": { S: "footwear" },
      "sku": { S: "hiking-sku-01" },
      "size": { N: "9" }
    }
  };

  try {
    const data = await client.send(new PutItemCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}
addProduct();
```

### 高階用戶端 (`DynamoDBDocumentClient`)
<a name="programming-with-javascript-high-level-client"></a>

高階 DynamoDB 文件用戶端提供內建的便利功能，例如不需要手動封送資料，以及允許使用標準 JavaScript 物件直接讀取和寫入。[`lib-dynamodb` 文件](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-lib-dynamodb/)提供優點清單。

若要執行個體化 `DynamoDBDocumentClient`，請建構低階 `DynamoDBClient`，然後使用 `DynamoDBDocumentClient` 包裝它。函數命名慣例在兩個套件之間略有不同。例如，低階使用 `PutItemCommand`，而高階使用 `PutCommand`。不同的名稱允許兩組函數在相同的內容中共存，讓您可以在相同的指令碼中混合兩者。

```
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, PutCommand } = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});

const docClient = DynamoDBDocumentClient.from(client);

async function addProduct() {
  const params = {
    TableName: "products",
    Item: {
      id: "Product01",
      description: "Hiking Boots",
      category: "footwear",
      sku: "hiking-sku-01",
      size: 9,
    },
  };

  try {
    const data = await docClient.send(new PutCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}

addProduct();
```

當您使用 `GetItem`、`Query` 或 `Scan` 等 API 操作讀取項目時，使用模式是一致的。

## 使用 marshall 公用程式函數
<a name="programming-with-javascript-using-marshall-utility"></a>

您可以自行使用低階用戶端和封送或取消封送資料類型。公用程式套件 [util-dynamodb](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-util-dynamodb/) 具有 `marshall()` 公用程式函數，可接受 JSON 並產生 DynamoDB JSON，以及反向執行的 `unmarshall()` 函數。下列範例使用低階用戶端搭配由 `marshall()` 呼叫處理的資料封送。

```
const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");
const { marshall } = require("@aws-sdk/util-dynamodb");

const client = new DynamoDBClient({});

async function addProduct() {
  const params = {
    TableName: "products",
    Item: marshall({
      id: "Product01",
      description: "Hiking Boots",
      category: "footwear",
      sku: "hiking-sku-01",
      size: 9,
    }),
  };

  try {
    const data = await client.send(new PutItemCommand(params));
  } catch (error) {
    console.error("Error:", error);
  }
}
addProduct();
```

## 讀取項目
<a name="programming-with-javascript-reading-items"></a>

若要從 DynamoDB 資料表讀取項目，請使用 `GetItem` API 操作。與 `PutItem` 命令類似，您可以選擇使用低階用戶端或高階文件用戶端。以下範例示範如何使用高階文件用戶端擷取項目。

```
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { DynamoDBDocumentClient, GetCommand } = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});

const docClient = DynamoDBDocumentClient.from(client);

async function getProduct() {
  const params = {
    TableName: "products",
    Key: {
      id: "Product01",
    },
  };

  try {
    const data = await docClient.send(new GetCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}

getProduct();
```

使用 `Query` API 操作讀取多個項目。您可以使用低階用戶端或文件用戶端。以下範例使用高階文件用戶端。

```
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const {
  DynamoDBDocumentClient,
  QueryCommand,
} = require("@aws-sdk/lib-dynamodb");

const client = new DynamoDBClient({});

const docClient = DynamoDBDocumentClient.from(client);

async function productSearch() {
  const params = {
    TableName: "products",
    IndexName: "GSI1",
    KeyConditionExpression: "#category = :category and begins_with(#sku, :sku)",
    ExpressionAttributeNames: {
      "#category": "category",
      "#sku": "sku",
    },
    ExpressionAttributeValues: {
      ":category": "footwear",
      ":sku": "hiking",
    },
  };

  try {
    const data = await docClient.send(new QueryCommand(params));
    console.log('result : ' + JSON.stringify(data));
  } catch (error) {
    console.error("Error:", error);
  }
}

productSearch();
```

## 條件式寫入
<a name="programming-with-javascript-conditional-writes"></a>

DynamoDB 寫入操作可以指定邏輯條件表達式，必須評估為 true 才能繼續寫入。如果條件未評估為 true，寫入操作會產生例外狀況。條件表達式可以檢查項目是否已存在，或其屬性是否符合特定限制條件。

`ConditionExpression = "version = :ver AND size(VideoClip) < :maxsize" `

當條件式表達式失敗時，您可以使用 `ReturnValuesOnConditionCheckFailure` 來請求錯誤回應包含不符合條件的項目，以推斷問題所在。如需詳細資訊，請參閱[使用 Amazon DynamoDB 在高並行情況下處理條件式寫入錯誤](https://aws.amazon.com/blogs/database/handle-conditional-write-errors-in-high-concurrency-scenarios-with-amazon-dynamodb/)。

```
try {
      const response = await client.send(new PutCommand({
          TableName: "YourTableName",
          Item: item,
          ConditionExpression: "attribute_not_exists(pk)",
          ReturnValuesOnConditionCheckFailure: "ALL_OLD"
      }));
  } catch (e) {
      if (e.name === 'ConditionalCheckFailedException') {
          console.log('Item already exists:', e.Item);
      } else {
          throw e;
      }
  }
```

其他程式碼範例顯示 JavsScript SDK V3 用量的其他層面，可在 [JavaScript SDK V3 文件](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_dynamodb_code_examples.html)和 [DynamoDB-SDK-Examples GitHub 儲存庫](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/node.js)下取得。

## 分頁
<a name="programming-with-javascript-pagination"></a>

**Topics**
+ [使用 `paginateScan` 便利方法](#using-the-paginatescan-convenience-method)

`Scan` 或 `Query` 等讀取請求可能會傳回資料集中的多個項目。如果您使用 `Limit` 參數執行 `Scan` 或 `Query`，一旦系統讀取到該項目數時，就會傳送部分回應，而且您需要分頁才能擷取其他項目。

對於每個請求，系統最多只會讀取 1 MB 的資料。如果您包含 `Filter` 表達式，系統仍將從磁碟讀取最多 1 MB 的資料，但會傳回該 MB 中符合篩選條件的項目。篩選操作可能從頁面傳回 0 個項目，但在搜尋窮盡之前仍需要進一步分頁。

您應該在回應中尋找 `LastEvaluatedKey`，並在後續請求中使用它做為 `ExclusiveStartKey` 參數，以繼續資料擷取。這可做為書籤，如下列範例所述。

**注意**  
在第一次迭代時，該範例會傳遞 null `lastEvaluatedKey` 做為 `ExclusiveStartKey`，這是允許的。

使用 `LastEvaluatedKey` 的範例：

```
const { DynamoDBClient, ScanCommand } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

async function paginatedScan() {
  let lastEvaluatedKey;
  let pageCount = 0;

  do {
    const params = {
      TableName: "products",
      ExclusiveStartKey: lastEvaluatedKey,
    };

    const response = await client.send(new ScanCommand(params));
    pageCount++;
    console.log(`Page ${pageCount}, Items:`, response.Items);
    lastEvaluatedKey = response.LastEvaluatedKey;
  } while (lastEvaluatedKey);
}

paginatedScan().catch((err) => {
  console.error(err);
});
```

### 使用 `paginateScan` 便利方法
<a name="using-the-paginatescan-convenience-method"></a>



開發套件提供稱為 `paginateScan` 和 `paginateQuery` 的便利方法，可在幕後為您執行此操作並重複提出請求。使用標準 `Limit` 參數指定每個請求要讀取的項目數量上限。

```
const { DynamoDBClient, paginateScan } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

async function paginatedScanUsingPaginator() {
  const params = {
    TableName: "products",
    Limit: 100
  };

  const paginator = paginateScan({client}, params);

  let pageCount = 0;

  for await (const page of paginator) {
    pageCount++;
    console.log(`Page ${pageCount}, Items:`, page.Items);
  }
}

paginatedScanUsingPaginator().catch((err) => {
  console.error(err);
});
```

**注意**  
除非資料表很小，否則不建議採用定期執行完整資料表掃描的存取模式。

## 指定組態
<a name="programming-with-javascript-config"></a>

**Topics**
+ [逾時的組態](#programming-with-javascript-config-timeouts)
+ [保持連線的組態](#programming-with-javascript-config-keep-alive)
+ [重試的組態](#programming-with-javascript-config-retries)

設定 `DynamoDBClient` 時，您可以將組態物件傳遞至建構函數，以指定各種組態覆寫。例如，如果呼叫內容還不知道，您可以指定要連線的區域，或指定要使用的端點 URL。如果您想要針對 DynamoDB 本機版執行個體進行開發，這非常有用。

```
const client = new DynamoDBClient({
  region: "eu-west-1",
  endpoint: "http://localhost:8000",
});
```

### 逾時的組態
<a name="programming-with-javascript-config-timeouts"></a>

DynamoDB 使用 HTTPS 進行用戶端-伺服器通訊。您可以透過提供 `NodeHttpHandler` 物件來控制 HTTP 層的某些層面。例如，您可以調整金鑰逾時值 `connectionTimeout` 和 `requestTimeout`。`connectionTimeout` 是用戶端在嘗試建立連線後放棄連線時所等待的最長持續時間，以毫秒為單位。

`requestTimeout` 定義傳送請求後用戶端等待回應的時間長度，也以毫秒為單位。兩者的預設值都是零，表示逾時已停用，而且如果未收到回應，用戶端等待的時間將沒有極限。您應該將逾時設定為合理值，以便在發生網路問題時，請求會因逾時而發出錯誤，並可啟動新的請求。例如：

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { NodeHttpHandler } from "@smithy/node-http-handler";

const requestHandler = new NodeHttpHandler({
  connectionTimeout: 2000,
  requestTimeout: 2000,
});

const client = new DynamoDBClient({
  requestHandler
});
```

**注意**  
提供的範例使用 [Smithy](https://smithy.io/2.0/index.html) 匯入。Smithy 是一種用於定義服務和 SDK 的語言，屬於開放原始碼，並由 AWS維護。

除了設定逾時值之外，您還可以設定通訊端數量上限，以增加每個原始伺服器的並行連線數量。開發人員指南包含[設定 `maxSockets` 參數的詳細資訊](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-configuring-maxsockets.html)。

### 保持連線的組態
<a name="programming-with-javascript-config-keep-alive"></a>

使用 HTTPS 時，第一個請求一律需要一些來回通訊才能建立安全連線。HTTP Keep-Alive 允許後續請求重複使用已建立的連線，使請求更有效率並降低延遲。JavaScript V3 預設會啟用 HTTP Keep-Alive。

閒置連線可以保持運作的時間有限制。如果您有閒置連線，但希望下一個請求使用已建立的連線，請考慮每分鐘傳送定期請求。

**注意**  
請注意，在較舊的 SDK V2 中，保持連線預設為關閉，這表示每個連線都會在使用後立即關閉。如果使用 V2，您可以覆寫此設定。

### 重試的組態
<a name="programming-with-javascript-config-retries"></a>

當 SDK 收到錯誤回應，且 SDK 判斷該錯誤是可恢復的，例如限流例外狀況或暫時服務例外狀況時，將會再次重試。身為呼叫者的您不會察覺到這一切，但您可能會注意到請求需要更長的時間才能成功。

根據預設，適用於 JavaScript V3 的 SDK 會在放棄錯誤並將其傳遞至呼叫內容之前，發出總共 3 次請求。您可以調整這些重試次數和頻率。

`DynamoDBClient` 建構函數接受會限制將要嘗試多少次的 `maxAttempts` 設定。以下範例會將該值從預設值 3 提高為總計 5 次。如果您將其設定為 0 或 1，表示您不希望任何自動重試，並想要自行在擷取區塊內處理任何可恢復的錯誤。

```
const client = new DynamoDBClient({
  maxAttempts: 5,
});
```

您也可以使用自訂重試策略來控制重試的時間。若要這樣做，請匯入 `util-retry` 公用程式套件，並建立自訂退避函數，根據目前的重試計數計算重試之間的等待時間。

以下範例顯示，如果第一次嘗試失敗，最多嘗試 5 次，延遲為 15、30、90 和 360 毫秒。自訂退避函數 ` calculateRetryBackoff` 會接受重試嘗試次數 (從第一次重試的 1 開始) 來計算延遲，並傳回該請求應等待的毫秒數。

```
const { ConfiguredRetryStrategy } = require("@aws-sdk/util-retry");

const calculateRetryBackoff = (attempt) => {
  const backoffTimes = [15, 30, 90, 360];
  return backoffTimes[attempt - 1] || 0;
};

const client = new DynamoDBClient({
  retryStrategy: new ConfiguredRetryStrategy(
    5, // max attempts.
    calculateRetryBackoff // backoff function.
  ),
});
```

## 等待程式
<a name="programming-with-javascript-waiters"></a>

DynamoDB 用戶端包含兩個有用的[等待程式函數](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/dynamodb/wait/index.html#cli-aws-dynamodb-wait)，當您希望程式碼等待資料表修改完成後才繼續執行時，可在建立、修改或刪除資料表時使用。例如，您可以部署資料表、呼叫 `waitUntilTableExists` 函數，而且程式碼會封鎖，直到資料表變成 **ACTIVE** 為止。等待程式每 20 秒會以 `describe-table` 輪詢一次 DynamoDB 服務。

```
import {waitUntilTableExists, waitUntilTableNotExists} from "@aws-sdk/client-dynamodb";

… <create table details>

const results = await waitUntilTableExists({client: client, maxWaitTime: 180}, {TableName: "products"});
if (results.state == 'SUCCESS') {
  return results.reason.Table
}
console.error(`${results.state} ${results.reason}`);
```

`waitUntilTableExists` 功能只會在可以執行會顯示資料表狀態 **ACTIVE** 的 `describe-table` 命令時傳回控制項。這可確保您可以使用 `waitUntilTableExists` 等待建立完成，以及新增 GSI 索引等修改，這可能需要一些時間來套用，資料表才會返回 **ACTIVE** 狀態。

## 錯誤處理
<a name="programming-with-javascript-error-handling"></a>

在這裡的早期範例中，我們概括地發現了所有錯誤。不過，在實際的應用程式中，區分各種錯誤類型並實作更精確的錯誤處理非常重要。

DynamoDB 錯誤回應包含中繼資料，包括錯誤的名稱。您可以擷取錯誤，然後比對可能的錯誤情況字串名稱，以判斷如何繼續。對於伺服器端錯誤，您可以利用 `instanceof` 運算子搭配 `@aws-sdk/client-dynamodb` 套件匯出的錯誤類型，有效率地管理錯誤處理。

請務必注意，這些錯誤只有在所有重試都用盡之後才會顯示。如果重試錯誤，且最終接續成功呼叫，從程式碼的角度來看並沒有錯誤，只是延遲稍微增加了。重試會在 Amazon CloudWatch 圖表中顯示為失敗的請求，例如限流或錯誤請求。如果用戶端達到重試計數上限，則會放棄並產生例外狀況。這是用戶端表達其不會重試的方式。

以下是擷取錯誤並根據傳回的錯誤類型採取行動的程式碼片段。

```
import {
  ResourceNotFoundException
  ProvisionedThroughputExceededException,
  DynamoDBServiceException,
} from "@aws-sdk/client-dynamodb";

try {
  await client.send(someCommand);
} catch (e) {
    if (e instanceof ResourceNotFoundException) {
      // Handle ResourceNotFoundException
    } else if (e instanceof ProvisionedThroughputExceededException) {
      // Handle ProvisionedThroughputExceededException
    } else if (e instanceof DynamoDBServiceException) {
      // Handle DynamoDBServiceException
    } else {
      // Other errors such as those from the SDK
      if (e.name === "TimeoutError") {
        // Handle SDK TimeoutError.
      } else {
        // Handle other errors.
      }
    }
}
```

請參閱《DynamoDB 開發人員指南》**中的常見 [使用 DynamoDB 時發生錯誤](Programming.Errors.md) 錯誤字串。您可以在該 API 呼叫的文件中找到任何特定 API 呼叫的確切錯誤，例如[查詢 API 文件](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html)。

錯誤中繼資料包含其他屬性，視錯誤而定。對於 ` TimeoutError`，中繼資料包含已嘗試的次數和 `totalRetryDelay`，如下所示。

```
{
  "name": "TimeoutError",
  "$metadata": {
    "attempts": 3,
    "totalRetryDelay": 199
  }
}
```

如果您管理自己的重試政策，您會想要區分限流和錯誤：
+ **限流** (由 ` ProvisionedThroughputExceededException` 或 `ThrottlingException` 表示) 表示運作狀態良好的服務，通知您已超過 DynamoDB 資料表或分割區的讀取或寫入容量。每經過一毫秒，就能獲得更多讀取或寫入容量，因此您可以快速重試，例如每 50 毫秒，以嘗試存取該新發布的容量。

   使用限流時，您不需要特別使用指數退避，因為傳回限流對 DynamoDB 很輕量，而且不會向您收取每次請求的費用。指數退避會將較長的延遲指派給已等待最長時間的用戶端執行緒，以統計方式將 p50 和 p99 向外延伸。
+ **錯誤** (由 ` InternalServerError` 或 `ServiceUnavailable` 等表示) 表示服務的暫時性問題，可能是整個資料表，也可能是您正在讀取或寫入的分割區。發生錯誤時，您可以在重試之前暫停更長的時間，例如 250 毫秒或 500 毫秒，並使用抖動來交錯重試。

## 日誌
<a name="programming-with-javascript-logging"></a>

開啟記錄功能，以取得 SDK 正在執行之作業的詳細資訊。您可以在 `DynamoDBClient` 上設定參數，如以下範例所示。更多日誌資訊會顯示在主控台中，並包含中繼資料，例如狀態碼和耗用容量。如果您於本機上在終端機視窗中執行程式碼，日誌會顯示在該處。如果您在 中執行程式碼 AWS Lambda，且已設定 Amazon CloudWatch logs，則會在該處寫入主控台輸出。

```
const client = new DynamoDBClient({
  logger: console
});
```

您也可以連接到內部 SDK 活動，並在發生特定事件時執行自訂記錄。以下範例使用用戶端的 `middlewareStack` 攔截從 SDK 傳送的每個請求，並在發生時記錄該請求。

```
const client = new DynamoDBClient({});

client.middlewareStack.add(
  (next) => async (args) => {
    console.log("Sending request from AWS SDK", { request: args.request });
    return next(args);
  },
  {
    step: "build",
    name: "log-ddb-calls",
  }
);
```

`MiddlewareStack` 提供強大的勾點，用於觀察和控制 SDK 行為。如需詳細資訊，請參閱 部落格[簡介模組化 Middleware Stack 適用於 JavaScript 的 AWS SDK](https://aws.amazon.com/blogs/developer/middleware-stack-modular-aws-sdk-js/)。

## 考量事項
<a name="programming-with-javascript-considerations"></a>

在專案 適用於 JavaScript 的 AWS SDK 中實作 時，以下是一些需要考慮的進一步因素。

**模組系統**  
開發套件支援兩個模組系統：CommonJS 和 ES (ECMAScript)。CommonJS 使用 `require` 函數，而 ES 則使用 `import` 關鍵字。  

1. **CommonJS** – `const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");`

1. **ES (ECMAScript** – `import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";`
專案類型指定要使用的模組系統，並在 package.json 檔案的類型區段中指定。預設為 CommonJS。使用 `"type": "module"` 來指示 ES 專案。如果您有使用 CommonJS 套件格式的現有 Node.JS 專案，您仍然可以使用 .mjs 副檔名來命名函數檔案，以新增具有更現代化 SDK V3 匯入語法的函數。這將允許把程式碼檔案視為 ES (ECMAScript)。

**非同步操作**  
您將看到許多使用回呼的程式碼範例，並承諾處理 DynamoDB 操作的結果。使用現代 JavaScript 不再需要這種複雜性，開發人員可以利用更簡潔且可讀取的非同步/等待語法進行非同步操作。

**Web 瀏覽器執行時期**  
使用 React 或 React Native 進行建置的 Web 和行動開發人員可以在其專案中使用適用於 JavaScript 的 SDK。使用舊版的 SDK V2，Web 開發人員必須將完整的 SDK 載入瀏覽器，並參考託管於 https://sdk.amazonaws.com/js/ 的 SDK 映像。  
使用 V3 時，您可以使用 Webpack 將所需的 V3 用戶端模組和所有必要的 JavaScript 函數綁定到單一 JavaScript 檔案中，並將其新增至 HTML 頁面 `<head>` 中的指令碼標籤，如 SDK 文件的[瀏覽器指令碼入門](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-started-browser.html)一節所述。

**DAX 資料平面操作**  
適用於 JavaScript V3 的 SDK 支援 Amazon DynamoDB Streams Accelerator (DAX) 資料平面操作。

# 使用 程式設計 DynamoDB AWS SDK for Java 2.x
<a name="ProgrammingWithJava"></a>

此程式設計指南為想要搭配 Java 使用 Amazon DynamoDB 的程式設計人員提供指導。本指南涵蓋不同的概念，包括抽象層、組態管理、錯誤處理、控制重試政策和管理保持連線。

**Topics**
+ [關於 AWS SDK for Java 2.x](#AboutProgrammingWithJavaSDK)
+ [開始使用](#GetStartedProgrammingWithJavaSDK)
+ [適用於 Java 2.x 的 SDK 文件](#ProgrammingWithJavaUseDoc)
+ [支援的介面](#JavaInterfaces)
+ [其他程式碼範例](#AdditionalCodeEx)
+ [同步和非同步程式設計](#SyncAsyncProgramming)
+ [HTTP 用戶端](#HttpClients)
+ [Config](#ConfigHttpClient)
+ [錯誤處理](#JavaErrorHandling)
+ [AWS 請求 ID](#JavaRequestID)
+ [日誌](#JavaLogging)
+ [分頁](#JavaPagination)
+ [資料類別註釋](#JavaDataClassAnnotation)

## 關於 AWS SDK for Java 2.x
<a name="AboutProgrammingWithJavaSDK"></a>

您可以使用 官方從 Java 存取 DynamoDB 適用於 Java 的 AWS SDK。適用於 Java 的 SDK 有兩個版本：1.x 和 2.x。1.x 版本已於 2024 年 1 月 12 日[宣布](https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-aws-sdk-for-java-v1-x-on-december-31-2025/)終止支援。它將在 2024 年 7 月 31 日進入維護模式，並將於 2025 年 12 月 31 日終止支援。對於新開發，我們強烈建議您使用 2.x，該版本於 2018 年首次發行。本指南專門針對 2.x，且僅著重於與 DynamoDB 相關的 SDK 部分。

如需 AWS SDKs，請參閱《 [AWS SDK 和工具參考指南》中的 SDK 和工具維護政策和](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html) [AWS SDKs 和工具版本支援矩陣](https://docs.aws.amazon.com/sdkref/latest/guide/version-support-matrix.html)。 *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 1.x 有一個名為 的 DynamoDB 套件`com.amazonaws.dynamodbv2`。套件名稱中的「v2」不表示其適用於 Java 2 (J2SE)。相反地，「v2」表示套件支援 DynamoDB 低階 API 的[第二個版本](CurrentAPI.md)，而非低階 API 的[原始版本](Appendix.APIv20111205.md)。

### 支援 Java 版本
<a name="SupportedJavaVersions"></a>

 AWS SDK for Java 2.x 提供長期支援 (LTS) [Java 版本](https://github.com/aws/aws-sdk-java-v2?tab=readme-ov-file#maintenance-and-support-for-java-versions)的完整支援。

## 開始使用 AWS SDK for Java 2.x
<a name="GetStartedProgrammingWithJavaSDK"></a>

下列教學課程說明如何使用 [Apache Maven](https://maven.apache.org/) 來定義適用於 Java 2.x 的 SDK 的相依性。本教學課程也說明如何撰寫連線至 DynamoDB 的程式碼，以列出可用的 DynamoDB 資料表。本指南中的教學課程是以《*AWS SDK for Java 2.x 開發人員指南*》中的 [AWS SDK for Java 2.x入門](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html)教學課程為基礎。我們已編輯本教學課程，以呼叫 DynamoDB 而非 Amazon S3。

**Topics**
+ [步驟 1：設定本教學課程](#GetStartedJavaSetup)
+ [步驟 2：建立專案](#GetStartedJavaProjectSetup)
+ [步驟 3：撰寫程式碼](#GetStartedJavaCode)
+ [步驟 4：建置並執行應用程式](#GetStartedRunJava)

### 步驟 1：設定本教學課程
<a name="GetStartedJavaSetup"></a>

在開始本教學課程之前，您需要以下項目：
+ 存取 DynamoDB 的許可。
+ 使用 設定單一登入存取的 Java AWS 服務 開發環境 AWS 存取入口網站。

若要設定本教學課程，請遵循 *AWS SDK for Java 2.x 開發人員指南*中[設定概觀](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-overview)中的指示。[設定具有單一登入存取設定的開發環境](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-credentials) (針對 Java SDK)，並擁有[作用中的 AWS 存取入口網站工作階段](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-login-sso)後，請繼續本教學課程[的步驟 2](#GetStartedJavaProjectSetup)。

### 步驟 2：建立專案
<a name="GetStartedJavaProjectSetup"></a>

若要建立本教學課程的專案，請執行 Maven 命令，該命令會提示您輸入如何設定專案。輸入並確認所有輸入後，Maven 會建立 `pom.xml` 檔案和建立 stub Java 檔案來完成建置專案。

1. 開啟終端機或命令提示視窗，然後導覽至您選擇的目錄，例如您的 `Desktop` 或 `Home` 資料夾。

1. 在終端輸入下列命令，然後按下 **Enter** 鍵。

   ```
   mvn archetype:generate \
      -DarchetypeGroupId=software.amazon.awssdk \
      -DarchetypeArtifactId=archetype-app-quickstart \
      -DarchetypeVersion=2.22.0
   ```

1. 針對每個提示，輸入第二欄中列出的值。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/ProgrammingWithJava.html)

1. 輸入最後一個值後，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` 專案檔案的內容。

#### `pom.xml`
<a name="ProjectSetupCollapse2"></a>

`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：撰寫程式碼
<a name="GetStartedJavaCode"></a>

下列程式碼顯示 Maven 建立的 `App` 類別。`main` 方法是應用程式的進入點，它會建立 `Handler` 類別的執行個體，然後呼叫其 `sendRequest` 方法。

#### `App` 類別
<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");
     }
 }
```

Maven 建立的 `DependencyFactory` 類別包含建置和傳回 [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) 執行個體的 `dynamoDbClient` 原廠方法。`DynamoDbClient` 執行個體使用 Apache 型 HTTP 用戶端的執行個體。這是因為您在 Maven 提示您使用哪個 HTTP 用戶端時指定了 `apache-client`。

下列程式碼顯示 `DependencyFactory` 類別。

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

`Handler` 類別包含您程式的主要邏輯。`App` 類別中建立了 `Handler` 的執行個體時，`DependencyFactory` 會提供 `DynamoDbClient` 服務用戶端。您的程式碼使用 `DynamoDbClient` 執行個體來呼叫 DynamoDB。

Maven 會產生具有 `TODO` 註解的下列 `Handler` 類別。教學課程中的下一個步驟會以程式碼取代 *`TODO`* 註解。

#### `Handler` 類別，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.
     }
 }
```

若要填入邏輯，請使用下列程式碼取代 `Handler` 類別的整個內容。`sendRequest` 方法已填入，並新增必要的匯入。

#### `Handler` 類別，已實作
<a name="code-collapse4"></a>

下列程式碼使用 [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) 執行個體來擷取現有資料表的清單。如果指定帳戶和 AWS 區域內存在資料表，則程式碼會使用 `Logger` 執行個體來記錄這些資料表的名稱。

```
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：建置並執行應用程式
<a name="GetStartedRunJava"></a>

在您建立專案並包含完整的 `Handler` 類別之後，請建置並執行應用程式。

1. 請確定您有一個作用中的 AWS IAM Identity Center 工作階段。若要確認，請執行 AWS Command Line Interface (AWS CLI) 命令 `aws sts get-caller-identity` 並檢查回應。如果您沒有作用中的工作階段，請參閱[使用 AWS CLI登入](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html#setup-login-sso)以取得指示。

1. 開啟終端機或命令提示視窗，然後導覽至您的專案目錄 `getstarted`。

1. 使用下列命令來建置專案：

   ```
   mvn clean package
   ```

1. 若要部署應用程式，請執行下列命令：

   ```
   mvn exec:java -Dexec.mainClass="org.example.App"
   ```

檢視檔案之後，請刪除物件，然後刪除儲存貯體。

#### 成功
<a name="GetStartedSuccessJava"></a>

如果您的 Maven 專案能建置且執行時沒有錯誤，恭喜您！您已成功使用適用於 Java 的 SDK 2.x 建置了第一個 Java 應用程式。

#### 清除
<a name="GetStartedCleanupJava"></a>

若要清除您在本教學課程中建立的資源，請刪除專案資料夾 `getstarted`。

## 檢閱 AWS SDK for Java 2.x 文件
<a name="ProgrammingWithJavaUseDoc"></a>

[AWS SDK for Java 2.x 開發人員指南](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html)涵蓋 SDK 在一切 AWS 服務中的所有層面。建議您檢閱下列主題：
+ [從 1.x 版移轉至 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/migration.html) – 包含 1.x 和 2.x 之間差異的詳細說明。本主題也包含如何使用兩個主要版本的指示，以並排方式顯示。
+ [適用於 Java 2.x SDK 的 DynamoDB 指南](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/examples-dynamodb.html) – 說明如何執行基本的 DynamoDB 操作：建立資料表、操作項目和擷取項目。這些範例使用低階介面。Java 有數個介面，如下節所述：[支援的介面](#JavaInterfaces)。

**提示**  
檢閱這些主題之後，請將 [AWS SDK for Java 2.x API 參考](https://sdk.amazonaws.com/java/api/latest/)加入書籤。它涵蓋所有項目 AWS 服務，我們建議您將其用作主要 API 參考。

## 支援的介面
<a name="JavaInterfaces"></a>

 AWS SDK for Java 2.x 支援下列界面，視您想要的抽象程度而定。

**Topics**
+ [低階介面](#LowLevelInterface)
+ [高階介面](#HighLevelInterface)
+ [文件介面](#DocumentInterface)
+ [使用 `Query` 範例比較各介面](#CompareJavaInterfacesQueryEx)

### 低階介面
<a name="LowLevelInterface"></a>

低階介面提供對基礎服務 API 的 1 對 1 映射。每個 DynamoDB API 都可以透過此介面使用。這表示低階介面可以提供完整的功能，但通常使用起來更冗長且複雜。例如，您必須使用 `.s()` 函數來保留字串，並使用 `.n()` 函數來保留數字。下列 [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) 範例使用低階介面插入項目。

```
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)");
    }
}
```

### 高階介面
<a name="HighLevelInterface"></a>

中的高階界面 AWS SDK for Java 2.x 稱為 DynamoDB 增強型用戶端。此介面提供更道地的程式碼撰寫體驗。

增強型用戶端提供一種在用戶端資料類別和旨在存放該資料的 DynamoDB 資料表之間映射的方法。您要在自己的程式碼中定義資料表及其對應模型類別之間的關係。然後，您可以依賴 SDK 來管理資料類型處理。如需增強型用戶端的詳細資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的 [DynamoDB 增強型用戶端 API](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/dynamodb-enhanced-client.html)。

下列 [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) 範例使用高階介面。在此範例中，名為 `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` 參考。

#### 使用不可變資料類別的高階介面
<a name="HighLevelInterfaceImmutableDataClasses"></a>

DynamoDB 增強型用戶端 API 的映射功能也適用於不可變的資料類別。不可變類別只有取得器，且需要 SDK 用來建立類別執行個體的建置器類別。Java 中的不可變性是一種常用的樣式，開發人員可用來建立沒有副作用的類別。這些類別在複雜多執行緒應用程式中的行為更可預測。不可變類別會使用 `@DynamoDbImmutable` 註釋，其採用建置器類別做為其輸入，而不是使用 [High-level interface example](#highleveleg) 中所示的 `@DynamoDbBean` 註釋。

下列範例採用建置器類別 `DynamoDbEnhancedClientImmutablePutItem` 做為輸入來建立資料表結構描述。然後，此範例提供結構描述做為 [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) 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); }
    }
}
```

#### 使用不可變資料類別和第三方樣板產生程式庫的高階介面
<a name="ImmutableDataClassesThirdPartyBoilerplateGenLib"></a>

不可變的資料類別 (如上例所示) 需要一些樣板程式碼。例如，除了 `Builder` 類別之外，對資料類別的取得器和設定器邏輯。例如 [Project Lombok](https://projectlombok.org/) 等第三方程式庫可協助您產生該類型的樣板程式碼。減少大部分樣板程式碼可協助您限制使用不可變資料類別和 AWS SDK 所需的程式碼數量。這進一步提高了生產力與程式碼的可讀性。如需詳細資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的[使用 Lombok 等第三方程式庫](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-use-immut.html#ddb-en-client-use-immut-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](https://projectlombok.org/features/Builder) – 為 Project Lombok 提供的資料類別產生複雜的建置器 API。
+ [@DynamoDbImmutable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/DynamoDbImmutable.html) – 將`DynamoDbImmutable`類別識別為 AWS 開發套件提供的 DynamoDB 可映射實體註釋。
+ [@Value](https://projectlombok.org/features/Value) – `@Data` 的不可變變體。根據預設，所有欄位都是私有和最終欄位，不會產生設定器。Project Lombok 提供此註釋。

### 文件介面
<a name="DocumentInterface"></a>

 AWS SDK for Java 2.x 文件界面不需要指定資料類型描述項。資料類型是由資料本身的語義隱含的。此文件界面類似於 文件界面 適用於 Java 的 AWS SDK 1.x，但具有重新設計的界面。

以下 [Document interface example](#DocInterfaceEg) 顯示使用文件介面表示的 `PutItem` 呼叫。此範例也使用 EnhancedDocument。若要使用增強型文件 API 針對 DynamoDB 資料表執行命令，您必須先將資料表與文件資料表結構描述建立關聯，才能建立 `DynamoDBTable` 資源物件。文件資料表結構描述建置器需要主索引鍵和屬性轉換器提供者。

您可以使用 `AttributeConverterProvider.defaultProvider()` 來轉換預設類型的文件屬性。您可以使用自訂 `AttributeConverterProvider` 實作變更整體預設行為。您也可以變更單一屬性的轉換器。[AWS SDK 和工具參考指南](https://docs.aws.amazon.com/sdkref/latest/guide/version-support-matrix.html)提供有關如何使用自訂轉換器的更多詳細資訊和範例。其主要用途是用於沒有預設轉換器的網域類別屬性。使用自訂轉換器，您可以向 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 文件彼此轉換，您可以使用下列公用程式方法：
+ [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)) – 從 JSON 字串建立新的 EnhancedDocument 實體。
+ [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()) – 建立文件的 JSON 字串表示法，您可以在應用程式中使用，就像任何其他 JSON 物件一樣。

### 使用 `Query` 範例比較各介面
<a name="CompareJavaInterfacesQueryEx"></a>

本節顯示使用各種介面表示的相同 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) 呼叫。若要微調這些查詢的結果，請注意下列事項：
+ DynamoDB 以一個特定的分割區索引鍵值為目標，因此您必須完全指定分割區索引鍵。
+ 若要讓查詢目標僅購物車項目，排序索引鍵具有使用 `begins_with` 的索引鍵條件表達式。
+ 我們使用 `limit()` 將查詢限制為最多傳回 100 個項目。
+ 我們將 `scanIndexForward` 設定為 false。結果會依 UTF-8 位元組的順序傳回，這通常表示會先傳回數量最低的購物車項目。透過將 `scanIndexForward` 設定為 false，我們把順序反轉，並先傳回數量最高的購物車項目。
+ 我們會套用篩選條件，以移除不符合條件的任何結果。篩選的資料會耗用讀取容量，無論項目是否符合篩選條件。

**Example `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"));
    }
}
```

**Example `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"));

    }
}
```

**Example `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](#HighLevelImmutableDataClassEg) 範例。
**使用不可變資料類別和第三方樣板產生程式庫的高階介面**  
當您使用高階不可變資料類別執行 `Query` 時，程式碼會與高階介面範例相同，但實體類別 `YourItem` 或 `YourImmutableLombokItem` 的建構除外。如需詳細資訊，請參閱 [PutItem](#HighLevelImmutableDataClassEg) 範例。

## 其他程式碼範例
<a name="AdditionalCodeEx"></a>

如需如何搭配適用於 Java 2.x 的 SDK 使用 DynamoDB 的其他範例，請參閱下列程式碼範例儲存庫：
+ [官方 AWS 單一動作程式碼範例](https://docs.aws.amazon.com/code-library/latest/ug/java_2_dynamodb_code_examples.html)
+ [社群維護的單一動作程式碼範例](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/java)
+ [官方 AWS 案例導向程式碼範例](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/examples/SDK/java)

## 同步和非同步程式設計
<a name="SyncAsyncProgramming"></a>

為 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 傳回[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)物件，其中包含未來非同步操作的結果。當您對這些 `CompletableFuture` 物件呼叫 `get()` 或 `join()` 時，您的程式碼會封鎖，直到結果可用為止。如果您在提出請求的同時呼叫這些函數，則行為類似於純同步呼叫。

如需非同步程式設計的詳細資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的[使用非同步程式設計](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/asynchronous.html)。

## HTTP 用戶端
<a name="HttpClients"></a>

為了支援每個用戶端，有一個 HTTP 用戶端來處理與 AWS 服務的通訊。您可以插入替代 HTTP 用戶端，選擇具有最符合您應用程式特性的用戶端。有些更輕量；有些則有更多組態選項。

有些 HTTP 用戶端僅支援同步使用，有些僅支援非同步使用。如需可協助您為工作負載選取最佳 HTTP 用戶端的流程圖，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的 [HTTP 用戶端建議](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration.html#http-clients-recommend)。

下列清單顯示一些可能的 HTTP 用戶端：

**Topics**
+ [Apache 型 HTTP 用戶端](#ApacheHttpClient)
+ [`URLConnection` 型 HTTP 用戶端](#URLConnHttpClient)
+ [Netty 型 HTTP 用戶端](#NettyHttpClient)
+ [AWS CRT 型 HTTP 用戶端](#AWSCRTHttpClient)

### Apache 型 HTTP 用戶端
<a name="ApacheHttpClient"></a>

[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) 類別支援同步服務用戶端。這是同步使用的預設 HTTP 用戶端。如需有關 `ApacheHttpClient` 類別的資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的[設定 Apache 型 HTTP 用戶端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-apache.html)。

### `URLConnection` 型 HTTP 用戶端
<a name="URLConnHttpClient"></a>

[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) 類別是同步用戶端的另一個選項。它比 Apache 型 HTTP 用戶端載入更快，但功能較少。如需有關設定 `UrlConnectionHttpClient` 類別的資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的[設定 URLConnection 型 HTTP 用戶端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-url.html)。

### Netty 型 HTTP 用戶端
<a name="NettyHttpClient"></a>

`NettyNioAsyncHttpClient` 類別支援非同步用戶端。這是非同步使用的預設選擇。如需有關 `NettyNioAsyncHttpClient` 類別的資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的[設定 Netty 型 HTTP 用戶端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-netty.html)。

### AWS CRT 型 HTTP 用戶端
<a name="AWSCRTHttpClient"></a>

 AWS 通用執行期 (CRT) 程式庫中較新的 `AwsCrtHttpClient` 和 `AwsCrtAsyncHttpClient`類別是支援同步和非同步用戶端的更多選項。相較於其他 HTTP 用戶端， AWS CRT 提供：
+ 更快速的 SDK 啟動時間
+ 記憶體佔用空間較小
+ 延遲時間縮短
+ 連線運作狀態管理
+ DNS 負載平衡

如需有關設定 `AwsCrtHttpClient`和 `AwsCrtAsyncHttpClient`類別的資訊，請參閱《 *AWS SDK for Java 2.x 開發人員指南*》中的[設定 AWS CRT 型 HTTP 用戶端](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-crt.html)。

 AWS CRT 型 HTTP 用戶端不是預設值，因為這會破壞現有應用程式的回溯相容性。不過，對於 DynamoDB，我們建議您將 AWS CRT 型 HTTP 用戶端用於同步和非同步用途。

如需 AWS CRT 型 HTTP 用戶端的簡介，請參閱《 *AWS 開發人員工具部落格*[》中的宣布 AWS CRT HTTP 用戶端的可用性 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/)。

## 設定 HTTP 用戶端
<a name="ConfigHttpClient"></a>

設定用戶端時，您可以提供各種組態選項，包括：
+ 設定 API 呼叫不同層面的逾時。
+ 啟用 TCP Keep-Alive。
+ 遇到錯誤時控制重試政策。
+ 指定[執行攔截器](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/interceptors.html)執行個體可以修改的執行屬性。執行攔截器可以編寫程式碼來攔截 API 請求和回應的執行。這可讓您即時執行發布指標和修改傳輸中請求等任務。
+ 新增或操作 HTTP 標頭。
+ 啟用[用戶端效能指標](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/metrics.html)的追蹤。使用此功能可協助您收集應用程式中的服務用戶端指標並在 Amazon CloudWatch 中分析輸出。
+ 指定要用於排程任務的替代執行器服務，例如非同步重試嘗試和逾時任務。

您可以提供 [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) 物件給服務用戶端 `Builder` 類別以控制組態。您會在下列各節的一些程式碼範例中看到此情況。

`ClientOverrideConfiguration` 提供標準組態選擇。不同的可插入 HTTP 用戶端也有實作特定的組態可能性。

**Topics**
+ [逾時組態](#TimeoutConfig)
+ [RetryMode](#RetryMode)
+ [DefaultsMode](#DefaultsMode)
+ [Keep-Alive 組態](#KeepAliveConfig)

### 逾時組態
<a name="TimeoutConfig"></a>

您可以調整用戶端組態，以控制與服務呼叫相關的各種逾時。與其他 AWS 服務相比，DynamoDB 提供較低的延遲。因此，您可能想要將這些屬性調整為較低的逾時值，以便在發生聯網問題時快速檢錯。

您可以在 DynamoDB 用戶端上使用 `ClientOverrideConfiguration`，或針對基礎 HTTP 用戶端實作變更詳細的組態選項，以自訂延遲相關行為。

您可以使用 `ClientOverrideConfiguration` 來設定下列具影響力的屬性：
+ `apiCallAttemptTimeout` – 在放棄和逾時之前，等待 HTTP 請求完成一次嘗試的時間長度。
+ `apiCallTimeout` – 用戶端完全執行 API 呼叫所需的時間量。這包括由所有 HTTP 請求組成的請求處理常式執行，包括重試。

 AWS SDK for Java 2.x 提供一些逾時選項的[預設值](https://github.com/aws/aws-sdk-java-v2/blob/a0c8a0af1fa572b16b5bd78f310594d642324156/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java#L134)，例如連線逾時和通訊端逾時。SDK 不提供 API 呼叫逾時或個別 API 呼叫嘗試逾時的預設值。如果未在 `ClientOverrideConfiguration` 中設定這些逾時，則 SDK 會使用通訊端逾時值，而非整體 API 呼叫逾時。通訊端的預設逾時值為 30 秒。

### RetryMode
<a name="RetryMode"></a>

另一個與您應該考慮的逾時組態相關的組態是 `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](#numRetries) 覆寫，否則它最多會執行總共 3 次嘗試。
+ `adaptive` – 以 `standard` 模式為基礎，並動態限制 AWS 請求率，使成功率最大化。這可能會因為請求延遲而發生。當可預測延遲很重要時，我們不建議使用自適應重試模式。

您可以在 *AWS SDK 和工具參考指南*的[重試行為](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html)主題中找到這些重試模式的擴展定義。

#### 重試政策
<a name="RetryPolicies"></a>

所有 `RetryMode` 組態都有以一或多個 [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/RetryPolicy.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/retry/RetryPolicy.html)。對於 DynamoDB SDK 用戶端實作的重試行為而言，[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) 特別重要。此條件會限制 SDK 使用權杖儲存貯體演算法進行的重試次數。根據選取的重試模式，限流例外狀況可能會也可能不會從 `TokenBucket` 中減去權杖。

當用戶端遇到可重試的錯誤，例如限流例外狀況或暫時性伺服器錯誤時，SDK 會自動重試請求。您可以控制這些重試的次數和速度。

設定用戶端時，您可以提供支援下列參數的 `RetryPolicy`：
+ `numRetries` – 請求視為失敗之前應套用的重試次數上限。無論您使用的重試模式為何，預設值都是 8。
**警告**  
請務必在適當考量後變更此預設值。
+ `backoffStrategy` – 要套用至重試的 [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)，預設策略為 [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)。此策略會根據目前的次數或重試次數、基本延遲和最大退避時間，在額外重試之間執行指數延遲。然後，它會新增抖動以提供一點隨機性。無論重試模式為何，指數延遲中使用的基本延遲為 25 毫秒。
+ `retryCondition` – [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) 決定要不要重試請求。根據預設，它會重試一組特定的 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
<a name="DefaultsMode"></a>

`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% 的準確性。如果無法判斷執行時期環境，則會使用標準模式。自動偵測可能會查詢[執行個體中繼資料和使用者資料](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)，這可能會導致延遲。如果啟動延遲對您的應用程式至關重要，我們建議您改為明確選擇 `DefaultsMode`。

您可以透過下列方式設定預設模式：
+ 直接在用戶端上，透過 `AwsClientBuilder.Builder#defaultsMode(DefaultsMode)`。
+ 在組態設定檔上，透過 `defaults_mode` 設定檔檔案屬性。
+ 全域，透過 `aws.defaultsMode` 系統屬性。
+ 全域，透過 `AWS_DEFAULTS_MODE` 環境變數。

**注意**  
對於 `legacy` 以外的任何模式，附加的預設值可能會隨著最佳實務的演進而變更。因此，如果您使用的是 `legacy` 以外的模式，建議您在升級 SDK 時執行測試。

*AWS SDK 和工具參考指南*中的[智慧組態預設](https://docs.aws.amazon.com/sdkref/latest/guide/feature-smart-config-defaults.html)會以不同的預設模式提供組態屬性及其預設值的清單。

您可以根據應用程式的特性和應用程式互動的 AWS 服務 來選擇預設模式值。

這些值的設定考量了 的廣泛選擇 AWS 服務 。對於 DynamoDB 資料表和應用程式都部署在一個區域中的典型 DynamoDB 部署，`in-region` 預設模式在 `standard` 預設模式之間最為相關。

**Example 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 用戶端的進階組態](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/http-configuration-crt.html#configuring-the-crt-based-http-client)。

### Keep-Alive 組態
<a name="KeepAliveConfig"></a>

啟用保持連線可以透過重複使用連線來減少延遲。有兩種不同類型的保持連線：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 上使用登錄值來執行此操作。

**Example 在 Apache 型 HTTP 用戶端上啟用 TCP Keep-Alive**  

```
DynamoDbClient client = DynamoDbClient.builder()
    .httpClientBuilder(ApacheHttpClient.builder().tcpKeepAlive(true))
    .build();
```

**`URLConnection` 型 HTTP 用戶端**  
任何使用 `URLConnection` 型 HTTP 用戶端的同步用戶端 [https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html](https://docs.oracle.com/javase/8/docs/api/java/net/HttpURLConnection.html) 都沒有啟用保持連線的[機制](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html)。

**Example 在 Netty 型 HTTP 用戶端上啟用 TCP Keep-Alive**  

```
DynamoDbAsyncClient client = DynamoDbAsyncClient.builder()
    .httpClientBuilder(NettyNioAsyncHttpClient.builder().tcpKeepAlive(true))
    .build();
```

**Example 在 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();
```

## 錯誤處理
<a name="JavaErrorHandling"></a>

處理例外狀況時， AWS SDK for Java 2.x 會使用執行時間 （未勾選） 例外狀況。

涵蓋所有 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)，其延伸自 Java 未檢查的 `RuntimeException`。如果您發現這種情況，您將會擷取到 SDK 擲回的所有例外狀況。

`SdkServiceException` 具有名為 [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) 的子類別。此子類別表示與 AWS 服務通訊時的任何問題。它有一個名為 [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) 的子類別，表示與 DynamoDB 通訊時發生問題。如果您發現這種情況，您將會擷取到與 DynamoDB 相關的所有例外狀況，但沒有其他 SDK 例外狀況。

在 `DynamoDbException` 下有更具體的[例外狀況類型](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/TableAlreadyExistsException.html](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/ConditionalCheckFailedException.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/model/ConditionalCheckFailedException.html)：您已指定評估為 false 的條件。例如，您可能已嘗試對項目執行條件式更新，但屬性的實際值不符合條件中的預期值。以此方式失敗的請求不會重試。

其他情況則未定義特定的例外狀況。例如，當您的請求受到限流時，可能會擲回特定 `ProvisionedThroughputExceededException`，而在其他情況下則擲回更通用的 `DynamoDbException`。在任何一種情況下，您都可以檢查 `isThrottlingException()` 是否傳回 `true`，以判斷限流是否造成例外狀況。

根據您的應用程式需求，您可以擷取所有 `AwsServiceException` 或 `DynamoDbException` 執行個體。不過，在不同的情況下，您通常需要不同的行為。處理條件檢查失敗的邏輯與處理限流的邏輯不同。定義您要處理的例外路徑，並務必測試替代路徑。這可協助您確保可以處理所有相關案例。

如需可能遇到的常見錯誤清單，請參閱 [使用 DynamoDB 時發生錯誤](Programming.Errors.md)。另請參閱《*Amazon DynamoDB API 參考*》中的[常見錯誤](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/CommonErrors.html)。API 參考也為每個 API 操作 (例如 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) 操作) 提供可能的確切錯誤。如需處理例外狀況的資訊，請參閱《*AWS SDK for Java 2.x 開發人員指南*》中的 [AWS SDK for Java 2.x例外狀況處理](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/handling-exceptions.html)。

## AWS 請求 ID
<a name="JavaRequestID"></a>

每個請求都包含一個請求 ID，如果您使用 AWS 支援 來診斷問題，這對於提取該 ID 很有幫助。衍生自 `SdkServiceException` 的每個例外狀況都有可用來擷取請求 ID 的 [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()) 方法。

## 日誌
<a name="JavaLogging"></a>

使用 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 使用者手冊](https://www.slf4j.org/manual.html)。

每個記錄器都有特定的行為。根據預設，Log4j 2.x 記錄器會建立 `ConsoleAppender`，其會將日誌事件附加至 `System.out`，並預設為 `ERROR` 日誌層級。

SLF4J 輸出中包含的 SimpleLogger 記錄器預設為 `System.err`，並預設為 `INFO` 日誌層級。

對於任何生產部署，建議您將 `WARN` 的階層設定為 `software.amazon.awssdk`，以便從 SDK 的用戶端程式庫擷取任何重要訊息，同時限制輸出數量。

如果 SLF4J 在類別路徑上找不到支援的記錄器 (無 SLF4J 繫結)，則會預設為[無操作實作](https://www.slf4j.org/codes.html#noProviders)。此實作會導致將訊息記錄於 `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 記錄](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/logging-slf4j.html)。

如果您使用 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 記錄
<a name="JavaReqIDLogging"></a>

當發生問題時，您可以在例外狀況中找到請求 ID。不過，如果您想要未產生例外狀況的請求 ID，則可以使用記錄功能。

`software.amazon.awssdk.request` 記錄器會在 `DEBUG` 層級輸出請求 ID。下列範例延伸先前的 [configuration example](#Log4j2ConfigEg)，將根記錄器層級保持在 `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
```

## 分頁
<a name="JavaPagination"></a>

有些請求，例如 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) 和 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html)，會限制單一請求傳回的資料大小，並要求您重複提出請求以提取後續頁面。

您可以使用 `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` 方法，例如 [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)) 和 [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))，SDK 會負責處理分頁。這些方法的傳回類型是自訂可迭代物件，可用來逐一查看所有頁面。SDK 會在內部為您處理服務呼叫。您可以使用 Java 串流 API 處理 `QueryPaginator` 的結果，如下列範例所示。

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

## 資料類別註釋
<a name="JavaDataClassAnnotation"></a>

Java SDK 提供數個註釋，您可以將這些註釋放在資料類別的屬性上。這些註釋會影響 SDK 如何與屬性互動。透過新增註釋，您可以讓屬性做為隱含原子計數器、維護自動產生的時間戳記值，或追蹤項目版本號碼。如需詳細資訊，請參閱[資料類別註釋](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/ddb-en-client-anno-index.html)。

# 使用 DynamoDB 時發生錯誤
<a name="Programming.Errors"></a>

 本節說明執行時期錯誤和其處理方式。其中也會說明 Amazon DynamoDB 特有的錯誤訊息和程式碼。如需適用於所有 AWS 服務的常見錯誤清單，請參閱[存取管理](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/CommonErrors.html)

**Topics**
+ [錯誤元件](#Programming.Errors.Components)
+ [交易性錯誤](#Programming.Errors.TransactionalErrors)
+ [錯誤訊息和錯誤碼](#Programming.Errors.MessagesAndCodes)
+ [應用程式中的錯誤處理](#Programming.Errors.Handling)
+ [錯誤重試和指數退避](#Programming.Errors.RetryAndBackoff)
+ [批次操作和錯誤處理](#Programming.Errors.BatchOperations)

## 錯誤元件
<a name="Programming.Errors.Components"></a>

當您的程式傳送請求時，DynamoDB 會嘗試進行處理。如果請求成功，則 DynamoDB 會傳回 HTTP 成功狀態碼 (`200 OK`) 以及所請求操作的結果。

如果請求不成功，DynamoDB 會傳回錯誤。每個錯誤都會有三個元件：
+ HTTP 狀態碼 (例如 `400`)。
+ 例外狀況名稱 (例如 `ResourceNotFoundException`)。
+ 錯誤訊息 (例如 `Requested resource not found: Table: tablename not found`)。

 AWS SDKs 負責將錯誤傳播到您的應用程式，以便您可以採取適當的動作。例如，在 Java 程式中，您可以撰寫 `try-catch` 邏輯來處理 `ResourceNotFoundException`。

如果您不是使用 AWS SDK，則需要從 DynamoDB 剖析低階回應的內容。以下是這類回應的範例。

```
HTTP/1.1 400 Bad Request
x-amzn-RequestId: LDM6CJP8RMQ1FHKSC1RBVJFPNVV4KQNSO5AEMF66Q9ASUAAJG
Content-Type: application/x-amz-json-1.0
Content-Length: 240
Date: Thu, 15 Mar 2012 23:56:23 GMT

{"__type":"com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",
"message":"Requested resource not found: Table: tablename not found"}
```

## 交易性錯誤
<a name="Programming.Errors.TransactionalErrors"></a>

如需有關交易性錯誤的資訊，請參閱 [DynamoDB 中的交易衝突處理](transaction-apis.md#transaction-conflict-handling)

## 錯誤訊息和錯誤碼
<a name="Programming.Errors.MessagesAndCodes"></a>

以下是 DynamoDB 依 HTTP 狀態碼進行分組並傳回的例外狀況清單。*確定要重試嗎？*為*是*，則可以重新提交相同的請求。*確定要重試嗎？*為*否*，則需要先修正使用者端上的問題，再提交新的請求。

### HTTP 狀態碼 400
<a name="Programming.Errors.MessagesAndCodes.http400"></a>

HTTP `400` 狀態碼指出請求發生問題，例如身分驗證失敗、遺失必要參數，或超過資料表的佈建輸送量。您必須先修正應用程式中的問題，再重新提交請求。

**AccessDeniedException **  
訊息：*Access denied.* (存取遭拒。)  
用戶端未正確地簽署請求。如果您使用的是 AWS 軟體開發套件，系統會自動為您簽署請求；如果不是，則請移至*AWS 一般參考*中的 [Signature 第 4 版簽署程序](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)。  
OK to retry? (確定要重試嗎？) 否

**ConditionalCheckFailedException**  
訊息：*The conditional request failed.* (條件式請求失敗。)  
您已指定評估為 false 的條件。例如，您可能已嘗試對項目執行條件式更新，但屬性的實際值不符合條件中的預期值。  
OK to retry? (確定要重試嗎？) 否

**IncompleteSignatureException**  
訊息：*The request signature does not conform to standards. (請求簽章不符合 AWS 標準。)*  
請求簽章未包含所有必要元件。如果您使用的是 AWS 開發套件，系統會自動為您簽署請求；否則，請前往 中的 [Signature 第 4 版簽署程序](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)*AWS 一般參考*。  
OK to retry? (確定要重試嗎？) 否

**ItemCollectionSizeLimitExceededException**  
訊息：*Collection size exceeded.* (已超過集合大小。)  
針對具有本機次要索引的資料表，具有相同分割區索引鍵值的項目群組已超過 10 GB 的大小上限。如需項目集合的詳細資訊，請參閱 [本機次要索引中的項目集合](LSI.md#LSI.ItemCollections)。  
OK to retry? (確定要重試嗎？) 是

**LimitExceededException**  
訊息：*Too many operations for a given subscriber.* (指定訂閱用戶的操作太多。)  
並行控制平面操作太多。在 `CREATING`、`DELETING` 或 `UPDATING` 狀態中，資料表和索引的累積數量不能超過 500。  
OK to retry? (確定要重試嗎？) 是

**MissingAuthenticationTokenException**  
訊息：*Request must contain a valid (registered) AWS Access Key ID. (請求必須包含有效 (已註冊) AWS 存取金鑰 ID。)*  
請求未包含必要授權標頭，或其格式不正確。請參閱 [DynamoDB 低階 API](Programming.LowLevelAPI.md)。  
OK to retry? (確定要重試嗎？) 否

**ProvisionedThroughputExceededException**  
訊息：*You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. To view performance metrics for provisioned throughput vs. consumed throughput, open the [Amazon CloudWatch console](https://console.aws.amazon.com/cloudwatch/home). (您已超過資料表或一或多個全域次要索引的最大允許佈建輸送量。若要檢視佈建輸送量與使用輸送的效能指標，請開啟 Amazon CloudWatch 主控台。)*  
錯誤包含 `ThrottlingReason` 欄位清單，提供為何發生限流的特定內容，並遵循格式 `ResourceType+OperationType+LimitType` (例如 `TableReadProvisionedThroughputExceeded`) 和受影響資源的 ARN。這可協助您識別要限流的資源 (資料表或索引)、觸發限流的操作類型 (讀取或寫入)，以及超過的特定限制 (在此案例中為佈建容量)。如需診斷和解決限流問題的詳細資訊，請參閱 [限流診斷](throttling-diagnosing-workflow.md)。  
範例：您的請求率太高。DynamoDB AWS SDKs 會自動重試收到此例外狀況的請求。除非您的重試佇列太大無法完成，否則您的請求最後會成功。請使用 [錯誤重試和指數退避](#Programming.Errors.RetryAndBackoff) 來減少請求的頻率。  
OK to retry? (確定要重試嗎？) 是

**ReplicatedWriteConflictException**  
訊息：*另一個區域中的請求正在修改此請求中的一或多個項目。*  
範例：針對多區域強式一致性 (MRSC) 全域資料表中的項目請求寫入操作，該資料表目前正由另一個區域中的請求修改。  
OK to retry? (確定要重試嗎？) 是

**RequestLimitExceeded**  
訊息：*輸送量超過帳戶的目前輸送量限制。若要請求提高限制，請聯絡 AWS Support，網址為 https：//[https://aws.amazon.com/support](https://aws.amazon.com/support)*。  
錯誤包含 `ThrottlingReason` 欄位清單，提供為何發生限流的特定內容，並遵循格式 `ResourceType+OperationType+LimitType` (例如 `TableWriteAccountLimitExceeded` 或 `IndexReadAccountLimitExceeded`) 和受影響資源的 ARN。這可協助您識別正在限流的資源 (資料表或索引)、觸發限流的操作類型 (讀取或寫入)，以及已超過帳戶層級的服務配額。如需診斷和解決限流問題的詳細資訊，請參閱 [限流診斷](throttling-diagnosing-workflow.md)。  
範例：隨選請求率超過允許的帳戶輸送量且資料表無法進一步擴展。  
OK to retry? (確定要重試嗎？) 是

**ResourceInUseException**  
訊息：*The resource which you are attempting to change is in use. *(正在使用您嘗試變更的資源。)  
範例：您已嘗試重新建立現在資料表，或刪除目前處於 `CREATING` 狀態的資料表。  
OK to retry? (確定要重試嗎？) 否

**ResourceNotFoundException **  
訊息：*Requested resource not found.* (找不到已註冊的資源。)  
範例：所請求的資料表不存在，或太早處於 `CREATING` 狀態。  
OK to retry? (確定要重試嗎？) 否

**ThrottlingException**  
訊息：*Rate of requests exceeds the allowed throughput.* (請求率超過允許的輸送量。)  
這個例外狀況會傳回為 AmazonServiceException 回應，並具備 THROTTLING\$1EXCEPTION 狀態碼。如果您執行[控制平面](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.API.html#HowItWorks.API.ControlPlane) API 操作太快，可能會傳回此例外狀況。  
對於使用隨需的資料表，如果您的請求率太高，任何[資料平面](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.API.html#HowItWorks.API.DataPlane) API 操作都可能會傳回此例外狀況。若要進一步了解隨需擴展，請參閱 [初始輸送量與擴展特性](on-demand-capacity-mode.md#on-demand-capacity-mode-initial)。  
錯誤包含 `ThrottlingReason` 欄位清單，提供為何發生限流的特定內容，並遵循格式 `ResourceType+OperationType+LimitType` (例如 `TableReadKeyRangeThroughputExceeded` 或 `IndexWriteMaxOnDemandThroughputExceeded`) 和受影響資源的 ARN。此資訊可協助您識別要限流的資源 (資料表或索引)、觸發限流的操作類型 (讀取或寫入)，以及超過的特定限制 (分割區限制或隨需最大輸送量)。如需診斷和解決限流問題的詳細資訊，請參閱 [限流診斷](throttling-diagnosing-workflow.md)。  
OK to retry? (確定要重試嗎？) 是

**UnrecognizedClientException**  
訊息：*The Access Key ID or security token is invalid.* (存取金鑰 ID 或安全字符無效。)  
請求簽章不正確。最可能的原因是無效的 AWS 存取金鑰 ID 或私密金鑰。  
OK to retry? (確定要重試嗎？) 是

**ValidationException**  
訊息：Varies, depending upon the specific error(s) encountered (會根據發生的特定錯誤而不同)  
可能會因數個原因而發生此錯誤，例如必要參數遺失、值超出範圍，或資料類型不符。錯誤訊息包含導致錯誤之請求特定部分的詳細資訊。  
OK to retry? (確定要重試嗎？) 否

### HTTP 狀態碼 5xx
<a name="Programming.Errors.MessagesAndCodes.http5xx"></a>

HTTP `5xx` 狀態碼指出 AWS必須解決的問題。這可能是暫時性錯誤，在此情況下，您可以重試請求，直到成功為止。如果不是，請前往 [AWS Service Health Dashboard](https://status.aws.amazon.com/)，確認服務是否發生任何操作問題。

如需詳細資訊，請參閱[如何解決 Amazon DynamoDB 中的 HTTP 5xx 錯誤？](https://aws.amazon.com/premiumsupport/knowledge-center/dynamodb-http-5xx-errors/)

**InternalServerError (HTTP 500)**  
DynamoDB 無法處理您的請求。  
OK to retry? (確定要重試嗎？) 是  
處理項目時，您可能會發生內部伺服器錯誤。在資料表生命週期期間，這些是預期錯誤。可以立即重試任何失敗的請求。  
當您在寫入作業上收到狀態碼 500 時，作業可能已成功或失敗。如果寫入操作是 `TransactWriteItem` 請求，則可以重試操作。如果寫入作業是單一項目寫入要求，例如 `PutItem`、`UpdateItem`，或 `DeleteItem`，那麼您的應用程序應該在重試操作之前讀取項目的狀態，和/或使用 [DynamoDB 條件表達式 CLI 範例](Expressions.ConditionExpressions.md)，以確保項目在重試後保持正確的狀態，無論先前的作業是成功還是失敗。如果冪等性是寫入操作的要求，請使用 [`TransactWriteItem`](transaction-apis.md#transaction-apis-txwriteitems)，它通過自動指定 `ClientRequestToken` 來消除多次嘗試執行相同動作的歧義。

**ServiceUnavailable (HTTP 503)**  
DynamoDB 目前無法使用。(這應該是暫時狀態)。  
OK to retry? (確定要重試嗎？) 是

## 應用程式中的錯誤處理
<a name="Programming.Errors.Handling"></a>

若要讓您的應用程式順暢執行，您需要新增邏輯來截獲並回應錯誤。一般方式包含使用 `try-catch` 區塊或 `if-then` 陳述式。

 AWS SDKs 會執行自己的重試和錯誤檢查。如果您在使用其中一個 AWS SDKs時發生錯誤，錯誤代碼和描述可協助您進行疑難排解。

您應該也會在回應中看到 `Request ID`。如果您需要與 AWS Support 合作來診斷問題， `Request ID`會很有幫助。

## 錯誤重試和指數退避
<a name="Programming.Errors.RetryAndBackoff"></a>

網路上有許多元件 (例如 DNS 伺服器、交換器、負載平衡器和其他項目) 可以在指定請求之生命週期中的任何階段產生錯誤。一般在網路環境中處理這些錯誤回應的技術，就是在用戶端應用程式中實作重試。這技術會提高應用程式的可靠性。

每個 AWS SDK 會自動實作重試邏輯。您可以視需要修改重試參數。例如，請考慮使用需要快速檢錯策略 (即發生錯誤時不允許重試) 的 Java 應用程式。透過 適用於 Java 的 AWS SDK，您可以使用 `ClientConfiguration`類別並提供 `maxErrorRetry`的值`0`來關閉重試。如需詳細資訊，請參閱程式設計語言的 AWS SDK 文件。

如果您不是使用 AWS SDK，您應該重試接收伺服器錯誤的原始請求 (5xx)。不過，用戶端錯誤 (4xx，非 `ThrottlingException` 或 `ProvisionedThroughputExceededException`) 指出您需要先修訂請求本身更正問題，然後再試一次。如需解決特定限流案例的詳細建議，請參閱 [DynamoDB 限流疑難排解](TroubleshootingThrottling.md)一節。

除了簡單的重試之外，每個 AWS SDK 還實作指數退避演算法，以更好地控制流程。指數退避的背後概念是，針對連續錯誤回應，讓重試之間的等待時間漸進拉長。例如，最多 50 毫秒再進行第一次重試、最多 100 毫秒再進行第二次重試、最多 200 毫秒再進行第三次重試，以此類推。不過，在一分鐘之後，如果請求未成功，則問題可能是請求大小超過佈建輸送量，而不是請求率。設定大約一分鐘停止的最大重試次數。如果請求未成功，請調查您的佈建輸送量選項。

**注意**  
 AWS SDKs 實作自動重試邏輯和指數退避。

大多數指數退避演算法會使用抖動 (隨機延遲)，以防止連續衝突。因為您在這些情況下並未嘗試避免這種衝突，所以不需要使用此亂數。不過，如果您使用並行用戶端，抖動有助於讓請求更快取得成功。如需詳細資訊，請參閱關於[指數退避和抖動](http://www.awsarchitectureblog.com/2015/03/backoff.html)的部落格文章。

## 批次操作和錯誤處理
<a name="Programming.Errors.BatchOperations"></a>

DynamoDB 低階 API 支援讀取和寫入的批次操作。`BatchGetItem` 從一或多個資料表讀取項目，`BatchWriteItem` 在一或多個資料表中放置或刪除項目。在其他非批次 DynamoDB 操作中，這些批次操作會實作為包裝函式。換言之，`BatchGetItem` 會針對批次中的每個項目調用 `GetItem` 一次。同樣地，`BatchWriteItem` 會針對批次中的每個項目適當地調用 `DeleteItem` 或 `PutItem`。

批次操作可以容忍批次中個別請求的失敗。例如，請考慮使用 `BatchGetItem` 請求來讀取五個項目。即使部分基礎 `GetItem` 請求失敗，這也不會導致整個 `BatchGetItem` 操作失敗。但若全部五個讀取操作均失敗，則整個 `BatchGetItem` 便會失敗。

批次操作會傳回失敗個別請求的資訊，讓您可以診斷問題，並重試操作。針對 `BatchGetItem`，會在回應的 `UnprocessedKeys` 值中傳回有問題的資料表和主索引鍵。針對 `BatchWriteItem`，在 `UnprocessedItems` 中會傳回類似的資訊。

最可能的失敗讀取或失敗寫入原因是*限流*。針對 `BatchGetItem`，批次請求中的一或多個資料表沒有足夠的已佈建讀取容量可支援操作。針對 `BatchWriteItem`，一或多個資料表沒有足夠的已佈建寫入容量。

如果 DynamoDB 傳回任何未處理的項目，您應該對這些項目重試批次操作。不過，*強烈建議您使用指數退避演算法*。如果您立即重試批次操作，則基於個別資料表上的限流，基礎讀取或寫入請求仍然可能會失敗。如果您使用指數退避來延遲批次操作，則批次中的個別請求較可能會成功。

**注意**  
 AWS SDKs提供更高層級的用戶端，可自動處理未處理的項目重試，因此您不需要自行實作此重試邏輯。例如：  
**Java** – 適用於 Java 的 AWS SDK v2 中的 [DynamoDB 增強型用戶端](DynamoDBEnhanced.md)和 v1 中的 [DynamoDBMapper](DynamoDBMapper.md) 都會在執行批次操作時自動重試未處理的項目。
**Python** – boto3 Table 資源會隱含地`batch_writer`處理未處理的項目重試，以進行批次寫入操作。如需詳細資訊，請參閱[使用資料表資源 batch\$1writer](programming-with-python.md#programming-with-python-batch-writer)。
如果您使用的是低階用戶端或不提供此行為的 SDK，您必須自行實作上述的重試邏輯。

# 搭配 AWS SDK 使用 DynamoDB
<a name="sdk-general-information-section"></a>

AWS 軟體開發套件 (SDKs) 適用於許多熱門的程式設計語言。每個 SDK 都提供 API、程式碼範例和說明文件，讓開發人員能夠更輕鬆地以偏好的語言建置應用程式。


| SDK 文件 | 代碼範例 | 
| --- | --- | 
| [適用於 C\$1\$1 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-cpp) | [適用於 C\$1\$1 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp) | 
| [AWS CLI](https://docs.aws.amazon.com/cli) | [AWS CLI 程式碼範例](https://docs.aws.amazon.com/code-library/latest/ug/cli_2_code_examples.html) | 
| [適用於 Go 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-go) | [適用於 Go 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/gov2) | 
| [適用於 Java 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-java) | [適用於 Java 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2) | 
| [適用於 JavaScript 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-javascript) | [適用於 JavaScript 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javascriptv3) | 
| [適用於 Kotlin 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-kotlin) | [適用於 Kotlin 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/kotlin) | 
| [適用於 .NET 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-net) | [適用於 .NET 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3) | 
| [適用於 PHP 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-php) | [適用於 PHP 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/php) | 
| [AWS Tools for PowerShell](https://docs.aws.amazon.com/powershell) | [AWS Tools for PowerShell 程式碼範例](https://docs.aws.amazon.com/code-library/latest/ug/powershell_5_code_examples.html) | 
| [適用於 Python (Boto3) 的 AWS SDK](https://docs.aws.amazon.com/pythonsdk) | [適用於 Python (Boto3) 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/python) | 
| [適用於 Ruby 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-ruby) | [適用於 Ruby 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/ruby) | 
| [適用於 Rust 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-rust) | [適用於 Rust 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1) | 
| [適用於 SAP ABAP 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-sapabap) | [適用於 SAP ABAP 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/sap-abap) | 
| [適用於 Swift 的 AWS SDK](https://docs.aws.amazon.com/sdk-for-swift) | [適用於 Swift 的 AWS SDK 程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/swift) | 

如需 DynamoDB 專屬範例，請參閱[使用 AWS SDKs DynamoDB 程式碼範例](service_code_examples.md)。

**可用性範例**  
找不到所需的內容嗎？ 請使用本頁面底部的**提供意見回饋**連結申請程式碼範例。