

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

# 第 1 版與第 2 版之間的 DynamoDB 映射 API 差異 適用於 Java 的 AWS SDK
<a name="ddb-mapping"></a>

DynamoDB 映射 APIs 第 1 版和第 2 版之間發生重大變更 適用於 Java 的 AWS SDK。在第 1 版中，您可以使用 `DynamoDBMapper` 來使用 Java POJOs。在第 2 版中，您可以使用 `DynamoDbEnhancedClient` 搭配更新的方法名稱、增強型結構描述定義選項，以及改善的類型安全性。

主要差異包括：
+ 新的方法名稱 （例如 `getItem` 而非 `load`)
+ 明確資料表結構描述建立
+ 同步和非同步操作的內建支援
+ 如何處理空白字串和組態的變更

本節涵蓋映射 API 變更、註釋差異、組態更新和遷移指引，以協助您從 v1 轉換`DynamoDBMapper`到 v2`DynamoDbEnhancedClient`。

**Contents**
+ [從適用於 Java 的 SDK 第 1 版到第 2 版映射程式庫的高階變更](dynamodb-mapping-high-level.md)
  + [匯入相依性差異](dynamodb-mapping-high-level.md#dynamodb-mapping-deps)
+ [適用於 Java 的 SDK 第 1 版和第 2 版之間的 DynamoDB 映射 APIs 變更](dynamodb-mapping-api-changes.md)
  + [建立用戶端](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-client)
  + [建立對 DynamoDB 資料表/索引的映射](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-mapping)
  + [資料表操作](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-tobleops)
  + [映射類別和屬性](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas)
    + [Bean 註釋](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos)
    + [V2 其他註釋](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos-v2-addnl)
  + [Configuration](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration)
    + [每個操作組態](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration-per-op)
  + [有條件](dynamodb-mapping-api-changes.md#dynamodb-mapping-conditionals)
  + [類型轉換](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv)
    + [預設轉換器](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-defaults)
    + [設定屬性的自訂轉換器](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-anno)
    + [新增類型轉換器工廠或供應商](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-factory)
+ [適用於 Java 的 SDK 第 1 版和第 2 版之間的字串處理差異](dynamodb-migration-string-handling.md)
+ [適用於 Java 的 SDK 第 1 版和第 2 版之間的樂觀鎖定差異](dynamodb-migrate-optimstic-locking.md)
+ [適用於 Java 的 SDK 第 1 版和第 2 版之間的流暢設定器差異](dynamodb-migrate-fluent-setters.md)

# 從適用於 Java 的 SDK 第 1 版到第 2 版映射程式庫的高階變更
<a name="dynamodb-mapping-high-level"></a>

每個程式庫中的映射用戶端名稱在 V1 和 V2 中不同：
+ V1 - DynamoDBMapper
+ V2 - DynamoDB 增強型用戶端

您以大致相同的方式與兩個程式庫互動：您執行個體化映射器/用戶端，然後將 Java POJO 提供給讀取和寫入這些項目至 DynamoDB 資料表APIs。這兩個程式庫也提供 POJO 類別的註釋，以指示用戶端如何處理 POJO。

移至 V2 時的顯著差異包括：
+ V2 和 V1 對低階 DynamoDB 操作使用不同的方法名稱。例如：    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/sdk-for-java/latest/developer-guide/dynamodb-mapping-high-level.html)
+ V2 提供多種方法來定義資料表結構描述，並將 POJOs對應至資料表。您可以選擇使用註釋，或使用建置器從程式碼產生的結構描述。V2 還提供結構描述的可變和不可變版本。
+ 使用 V2 時，您會特別將資料表結構描述建立為第一個步驟之一，而在 V1 中，則會視需要從註釋的類別推斷資料表結構描述。
+ V2 在增強型[用戶端 API 中包含文件 ](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html) API 用戶端，而 V1 使用[單獨的 API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html)。
+ 所有 APIs V2 中提供同步和非同步版本。

如需 V2 增強型用戶端的詳細資訊，請參閱本指南中的 [DynamoDB 映射一節](dynamodb-enhanced-client.md)。

## 匯入相依性差異
<a name="dynamodb-mapping-deps"></a>


| V1 | V2 | 
| --- | --- | 
|  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>com.amazonaws</groupId><br />      <artifactId>aws-java-sdk-bom</artifactId><br />      <version>1.X.X</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>com.amazonaws</groupId><br />    <artifactId>aws-java-sdk-dynamodb</artifactId><br />  </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>software.amazon.awssdk</groupId><br />      <artifactId>bom</artifactId><br />      <version>2.X.X*</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>software.amazon.awssdk</groupId><br />    <artifactId>dynamodb-enhanced</artifactId><br />  </dependency><br /></dependencies></pre>  | 

\$1 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

在 V1 中，單一相依性同時包含低階 DynamoDB API 和映射/文件 API，而在 V2 中，您可以使用`dynamodb-enhanced`成品相依性來存取映射/文件 API。`dynamodb-enhanced` 模組包含低階`dynamodb`模組的暫時性相依性。

# 適用於 Java 的 SDK 第 1 版和第 2 版之間的 DynamoDB 映射 APIs 變更
<a name="dynamodb-mapping-api-changes"></a>

## 建立用戶端
<a name="dynamodb-mapping-api-changes-client"></a>


****  

| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
|   正常執行個體化  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard()<br />    .withCredentials(credentialsProvider)<br />    .withRegion(Regions.US_EAST_1)<br />    .build();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbClient standardClient = DynamoDbClient.builder()<br />    .credentialsProvider(ProfileCredentialsProvider.create())<br />    .region(Region.US_EAST_1)<br />    .build();<br />DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .build();</pre>  | 
|   最小執行個體化  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();</pre>  | 
|   使用屬性轉換器\$1  |  <pre>DynamoDBMapper mapper = new DynamoDBMapper(standardClient, <br />                        attributeTransformerInstance);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .extensions(extensionAInstance, extensionBInstance)<br />    .build();</pre>  | 

\$1V2 中的延伸大致對應至 V1 中的屬性轉換器。[使用擴充功能自訂 DynamoDB 增強型用戶端操作](ddb-en-client-extensions.md) 本節包含 V2 中延伸模組的詳細資訊。

## 建立對 DynamoDB 資料表/索引的映射
<a name="dynamodb-mapping-api-changes-mapping"></a>

在 V1 中，您可以透過 Bean 註釋指定 DynamoDB 資料表名稱。在 V2 中，原廠方法 `table()`會產生`DynamoDbTable`代表遠端 DynamoDB 資料表的 執行個體。`table()` 方法的第一個參數是 DynamoDB 資料表名稱。


****  

| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
|   將 Java POJO 類別映射至 DynamoDB 資料表  |  <pre>@DynamoDBTable(tableName ="Customer")<br />public class Customer {<br />  ...<br />}</pre>  |  <pre>DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer",<br />    TableSchema.fromBean(Customer.class));</pre>  | 
|   映射至 DynamoDB 次要索引  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) DynamoDB 開發人員指南中討論[ V1 `query`方法](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html#DynamoDBMapper.Methods.query)的 區段會顯示完整的範例。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) 本指南中的 [使用次要索引](ddb-en-client-use-secindex.md)區段提供更多資訊。  | 

## 資料表操作
<a name="dynamodb-mapping-api-changes-tobleops"></a>

本節說明適用於大多數標準使用案例的 V1 和 V2 之間的操作 APIs。

在 V2 中，所有涉及單一資料表的操作都會在`DynamoDbTable`執行個體上呼叫，而不是在增強型用戶端上呼叫。增強型用戶端包含可將多個資料表設為目標的方法。

在下列名為*資料表操作*的資料表中，POJO 執行個體稱為 `item`或特定類型，例如 `customer1`。對於名為 的執行個體的 V2 範例， `table`是先前呼叫 `enhancedClient.table()`傳回執行個體參考的結果`DynamoDbTable`。

請注意，即使未顯示，大多數 V2 操作也可以使用流暢的消費者模式來呼叫。例如 

```
Customer customer = table.getItem(r → r.key(key));
  or
Customer customer = table.getItem(r → r.key(k -> k.partitionValue("id").sortValue("email")))
```

對於 V1 操作，*資料表操作* （下方） 包含一些常用表單，而不是所有超載表單。例如， `load()`方法具有下列過載：

```
mapper.load(Customer.class, hashKey)
mapper.load(Customer.class, hashKey, rangeKey)
mapper.load(Customer.class, hashKey, config)
mapper.load(Customer.class, hashKey, rangeKey, config)
mapper.load(item)
mapper.load(item, config)
```

*資料表操作* （下方） 顯示常用的表單：

```
mapper.load(item)
mapper.load(item, config)
```


**資料表操作**  

| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
|  將 Java POJO 寫入 DynamoDB 資料表 **DynamoDB 操作：**`PutItem`、 `UpdateItem`  |  <pre>mapper.save(item)<br />mapper.save(item, config)<br />mapper.save(item, saveExpression, config)</pre> 在 V1 中， `DynamoDBMapperConfig.SaveBehavior`和 註釋會決定要呼叫哪個低階 DynamoDB 方法。一般而言， `UpdateItem` 會在使用 `SaveBehavior.CLOBBER`和 時呼叫 `SaveBehavior.PUT`。自動產生的金鑰是特殊的使用案例，偶爾同時使用 `UpdateItem` `PutItem`和 。  |  <pre>table.putItem(putItemRequest)<br />table.putItem(item)<br />table.putItemWithResponse(item) //Returns metadata.<br /><br />updateItem(updateItemRequest)<br />table.updateItem(item)<br />table.updateItemWithResponse(item) //Returns metadata.</pre>  | 
|  從 DynamoDB 資料表將項目讀取至 Java POJO **DynamoDB 操作：** `GetItem`  |  <pre>mapper.load(item)<br />mapper.load(item, config)</pre>  |  <pre>table.getItem(getItemRequest)<br />table.getItem(item)<br />table.getItem(key)<br />table.getItemWithResponse(key) //Returns POJO with metadata.</pre>  | 
|  從 DynamoDB 資料表刪除項目 **DynamoDB 操作：** `DeleteItem`  |  <pre>mapper.delete(item, deleteExpression, config)</pre>  |  <pre>table.deleteItem(deleteItemRequest)<br />table.deleteItem(item)<br />table.deleteItem(key)</pre>  | 
|  查詢 DynamoDB 資料表或次要索引並傳回分頁清單 **DynamoDB 操作：** `Query`  |  <pre>mapper.query(Customer.class, queryExpression)<br />mapper.query(Customer.class, queryExpression, <br />                             mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> 將傳回的 `PageIterable.stream()`（延遲載入） 用於同步回應和非`PagePublisher.subscribe()`同步回應  | 
|  查詢 DynamoDB 資料表或次要索引並傳回清單 **DynamoDB 操作：** `Query`  |  <pre>mapper.queryPage(Customer.class, queryExpression)<br />mapper.queryPage(Customer.class, queryExpression, <br />                                 mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> 將傳回的 `PageIterable.items()`（延遲載入） 用於同步回應和非`PagePublisher.items.subscribe()`同步回應  | 
|  掃描 DynamoDB 資料表或次要索引並傳回分頁清單 **DynamoDB 操作：** `Scan`  |  <pre>mapper.scan(Customer.class, scanExpression)<br />mapper.scan(Customer.class, scanExpression, <br />                            mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> 將傳回的 `PageIterable.stream()`（延遲載入） 用於同步回應和非`PagePublisher.subscribe()`同步回應  | 
|  掃描 DynamoDB 資料表或次要索引並傳回清單 **DynamoDB 操作：** `Scan`  |  <pre>mapper.scanPage(Customer.class, scanExpression)<br />mapper.scanPage(Customer.class, scanExpression, <br />                                mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> 將傳回的 `PageIterable.items()`（延遲載入） 用於同步回應和非`PagePublisher.items.subscribe()`同步回應  | 
|  從批次中的多個資料表讀取多個項目 **DynamoDB 操作：** `BatchGetItem`  |  <pre>mapper.batchLoad(Arrays.asList(customer1, <br />                               customer2, <br />                               book1))<br />mapper.batchLoad(itemsToGet) <br />           // itemsToGet: Map<Class<?>, List<KeyPair>></pre>  |  <pre>enhancedClient.batchGetItem(batchGetItemRequest)<br /><br />enhancedClient.batchGetItem(r -> r.readBatches(<br />    ReadBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build(),<br />    ReadBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build()))<br /><br />// Iterate over pages with lazy loading or over all items <br />   from the same table.</pre>  | 
|  將多個項目寫入批次中的多個資料表 **DynamoDB 操作：** `BatchWriteItem`  |  <pre>mapper.batchSave(Arrays.asList(customer1, <br />                               customer2, <br />                               book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(batchWriteItemRequest)<br /><br />enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addPutItem(item2)<br />             .build()))</pre>  | 
|  從批次中的多個資料表刪除多個項目 **DynamoDB 操作：** `BatchWriteItem`  |  <pre>mapper.batchDelete(Arrays.asList(customer1, <br />                                 customer2, <br />                                 book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addDeleteItem(item1key)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  寫入/刪除批次中的多個項目 **DynamoDB 操作：** `BatchWriteItem`  |  <pre>mapper.batchWrite(Arrays.asList(customer1, book1), <br />                  Arrays.asList(customer2)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  執行交易寫入 **DynamoDB 操作：** `TransactWriteItems`  |  <pre>mapper.transactionWrite(transactionWriteRequest)</pre>  |  <pre>enhancedClient.transactWriteItems(transasctWriteItemsRequest)</pre>  | 
|  執行交易讀取 **DynamoDB 操作：** `TransactGetItems`  |  <pre>mapper.transactionLoad(transactionLoadRequest)</pre>  |  <pre>enhancedClient.transactGetItems(transactGetItemsRequest) </pre>  | 
|  取得查詢相符項目的計數 **DynamoDB 操作：**`Query`使用 `Select.COUNT`  |  <pre>mapper.count(Customer.class, queryExpression)</pre>  |  <pre>// Get the count from query results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.query(QueryEnhancedRequest.builder()<br />        .queryConditional(queryConditional)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.query(QueryEnhancedRequest.builder()<br />                .queryConditional(queryConditional)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  取得掃描相符項目的計數 **DynamoDB 操作：**`Scan`使用 `Select.COUNT`  |  <pre>mapper.count(Customer.class, scanExpression)</pre>  |  <pre>// Get the count from scan results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.scan(ScanEnhancedRequest.builder()<br />        .filterExpression(filterExpression)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.scan(ScanEnhancedRequest.builder()<br />                .filterExpression(filterExpression)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  在對應至 POJO 類別的 DynamoDB 中建立資料表 **DynamoDB 操作：** `CreateTable`  |  <pre>mapper.generateCreateTableRequest(Customer.class)</pre> 先前的陳述式會產生低階建立資料表請求；使用者必須在 DynamoDB 用戶端`createTable`上呼叫 。  |  <pre>table.createTable(createTableRequest)<br /><br />table.createTable(r -> r.provisionedThroughput(defaultThroughput())<br />    .globalSecondaryIndices(<br />        EnhancedGlobalSecondaryIndex.builder()<br />            .indexName("gsi_1")<br />            .projection(p -> p.projectionType(ProjectionType.ALL))<br />            .provisionedThroughput(defaultThroughput())<br />            .build()));</pre>  | 
|  在 DynamoDB 中執行平行掃描 **DynamoDB 操作：**`Scan`使用 `Segment`和 `TotalSegments` 參數  |  <pre>mapper.parallelScan(Customer.class, <br />                    scanExpression, <br />                    numTotalSegments)</pre>  |  使用者需要處理`scan`每個區段的工作者執行緒和呼叫： <pre>table.scan(r -> r.segment(0).totalSegments(5))</pre>  | 
|  將 Amazon S3 與 DynamoDB 整合，以存放智慧型 S3 連結  |  <pre>mapper.createS3Link(bucket, key)<br />mapper.getS3ClientCache()</pre>  |  不支援，因為它會耦合 Amazon S3 和 DynamoDB。  | 

## 映射類別和屬性
<a name="dynamodb-mapping-schemas"></a>

在 V1 和 V2 中，您可以使用 Bean 樣式註釋將類別映射至資料表。V2 也提供[其他方法來定義特定使用案例的結構描述](ddb-en-client-adv-features.md#ddb-en-client-adv-features-schm-overview)，例如使用不可變類別。

### Bean 註釋
<a name="dynamodb-mapping-schemas-annos"></a>

下表顯示 V1 和 V2 中使用的特定使用案例的同等 Bean 註釋。`Customer` 類別案例用於說明參數。

在 V2 中，註釋以及類別和列舉都遵循駱駝案例慣例，並使用「DynamoDb」，而不是「DynamoDB」。


| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
| 將類別映射至資料表 |  <pre>@DynamoDBTable (tableName ="CustomerTable")</pre>  | <pre>@DynamoDbBean<br />@DynamoDbBean(converterProviders = {...})</pre>呼叫 DynamoDbEnhancedClient\$1table()方法時會定義資料表名稱。 | 
| 將類別成員指定為資料表屬性  |  <pre>@DynamoDBAttribute(attributeName = "customerName")</pre>  |  <pre>@DynamoDbAttribute("customerName") </pre>  | 
| 指定類別成員是雜湊/分割區索引鍵 |  <pre>@DynamoDBHashKey </pre>  |  <pre>@DynamoDbPartitionKey</pre>  | 
| 指定類別成員是範圍/排序索引鍵 |  <pre>@DynamoDBRangeKey </pre>  |  <pre>@DynamoDbSortKey </pre>  | 
| 指定類別成員是次要索引雜湊/分割區索引鍵 |  <pre>@DynamoDBIndexHashKey </pre>  |  <pre>@DynamoDbSecondaryPartitionKey </pre>  | 
| 指定類別成員是次要索引範圍/排序索引鍵 |  <pre>@DynamoDBIndexRangeKey </pre>  |  <pre>@DynamoDbSecondarySortKey </pre>  | 
| 映射至資料表時忽略此類別成員 |  <pre>@DynamoDBIgnore </pre>  |  <pre>@DynamoDbIgnore</pre>  | 
| 將類別成員指定為自動產生的 UUID 金鑰屬性 |  <pre>@DynamoDBAutoGeneratedKey</pre>  |  <pre>@DynamoDbAutoGeneratedUuid </pre> 根據預設，不會載入提供此項目的延伸模組；您必須將延伸模組新增至用戶端建置器。  | 
| 將類別成員指定為自動產生的時間戳記屬性 |  <pre>@DynamoDBAutoGeneratedTimestamp</pre>  |  <pre>@DynamoDbAutoGeneratedTimestampAttribute</pre> 根據預設，不會載入提供此項目的延伸模組；您必須將延伸模組新增至用戶端建置器。  | 
| 將類別成員指定為自動遞增版本屬性 |  <pre>@DynamoDBVersionAttribute</pre>  |  <pre>@DynamoDbVersionAttribute</pre> 自動載入提供此功能的延伸模組。  | 
| 將類別成員指定為需要自訂轉換 |  <pre>@DynamoDBTypeConverted</pre>  |  <pre>@DynamoDbConvertedBy</pre>  | 
| 指定要儲存為不同屬性類型的類別成員 |  <pre>@DynamoDBTyped(<DynamoDBAttributeType>)</pre>  |  使用 `AttributeConverter`實作。V2 為常見 Java 類型提供許多內建轉換器。您也可以實作自己的自訂 `AttributeConverter`或 `AttributeConverterProvider`。請參閱本指南[控制屬性轉換](ddb-en-client-adv-features-conversion.md)中的 。  | 
| 指定可序列化為 DynamoDB 文件 (JSON 樣式文件） 或子文件的類別  |  <pre>@DynamoDBDocument</pre>  | 使用增強型文件 API。請參閱下列資源：[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) | 

### V2 其他註釋
<a name="dynamodb-mapping-schemas-annos-v2-addnl"></a>


| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
| 如果 Java 值為 null，則指定類別成員不要儲存為 NULL 屬性 | N/A |  <pre>@DynamoDbIgnoreNulls</pre>  | 
| 如果所有屬性都是 null，請將類別成員指定為空白物件 | N/A |  <pre>@DynamoDbPreserveEmptyObject</pre>  | 
| 為類別成員指定特殊更新動作 | N/A |  <pre>@DynamoDbUpdateBehavior</pre>  | 
| 指定不可變類別 | N/A |  <pre>@DynamoDbImmutable</pre>  | 
| 將類別成員指定為自動遞增的計數器屬性 | N/A |  <pre>@DynamoDbAtomicCounter</pre> 自動載入提供此功能的延伸模組。  | 

## Configuration
<a name="dynamodb-mapping-configuration"></a>

在 V1 中，您通常會使用 執行個體來控制特定行為`DynamoDBMapperConfig`。您可以在建立映射器或提出請求時提供組態物件。在 V2 中，組態專屬於 操作的請求物件。


| 使用案例 | V1 | V1 中的預設值 | V2 | 
| --- | --- | --- | --- | 
|  |  <pre>DynamoDBMapperConfig.builder()</pre>  |  |  | 
| 批次載入/寫入重試策略 |  <pre>  .withBatchLoadRetryStrategy(loadRetryStrategy)</pre> <pre>  .withBatchWriteRetryStrategy(writeRetryStrategy)</pre>  | 重試失敗的項目 | 在基礎 上設定重試策略DynamoDBClient。請參閱本指南[在 中設定重試行為 AWS SDK for Java 2.x](retry-strategy.md)中的 。 | 
| 一致的讀取 |  <pre>  .withConsistentReads(CONSISTENT)</pre>  | EVENTUAL | 根據預設，讀取操作的一致性讀取為 false。在請求物件.consistentRead(true)上使用 覆寫 。 | 
| 具有 marshallers/unmarshallers 集的轉換結構描述 |  <pre>  .withConversionSchema(conversionSchema)</pre> 靜態實作提供與舊版的回溯相容性。  | V2\$1COMPATIBLE | 不適用。這是舊版功能，指 DynamoDB (V1) 儲存資料類型的最早版本，而且此行為不會保留在增強型用戶端中。DynamoDB V1 中的行為範例是將布林值儲存為數字而非布林值。 | 
| 資料表名稱 |  <pre>  .withObjectTableNameResolver()<br />  .withTableNameOverride() <br />  .withTableNameResolver()</pre> 靜態實作提供與舊版的回溯相容性  | 使用 類別的註釋或猜測 |  呼叫 `DynamoDbEnhancedClient#table()`方法時會定義資料表名稱。  | 
| 分頁載入策略 |  <pre>  .withPaginationLoadingStrategy(strategy)</pre>  選項為：LAZY\$1`EAGER_LOADING`、 `LOADING`或 `ITERATION_ONLY`  | LAZY\$1LOADING |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html)  | 
| 請求指標集合 |  <pre>  .withRequestMetricCollector(collector)</pre>  | null | 在建置標準 DynamoDB 用戶端metricPublisher()ClientOverrideConfiguration時使用 。 | 
| 儲存行為 |  <pre>  .withSaveBehavior(SaveBehavior.CLOBBER) </pre> 選項為 `UPDATE`、`CLOBBER`、`APPEND_SET`、 `PUT`或 `UPDATE_SKIP_NULL_ATTRIBUTES`。  | UPDATE |  在 V2 中，您可以明確呼叫 `putItem()`或 `updateItem()` 。 `CLOBBER or PUT`：v 2 中的對應動作正在呼叫 `putItem()`。沒有特定的`CLOBBER`組態。 `UPDATE`：對應至 `updateItem()` `UPDATE_SKIP_NULL_ATTRIBUTES`：對應至 `updateItem()`。使用請求設定`ignoreNulls`和註釋/標籤 控制更新行為`DynamoDbUpdateBehavior`。 `APPEND_SET`：不支援  | 
| 類型轉換器工廠 |  <pre>  .withTypeConverterFactory(typeConverterFactory) </pre>  | 標準類型轉換器 |  使用 在 Bean 上設定 <pre>@DynamoDbBean(converterProviders = {ConverterProvider.class, <br />        DefaultAttributeConverterProvider.class})</pre>  | 

### 每個操作組態
<a name="dynamodb-mapping-configuration-per-op"></a>

在 V1 中，某些操作，例如 `query()`，可透過提交至操作的「運算式」物件進行高度設定。例如：

```
DynamoDBQueryExpression<Customer> emailBwQueryExpr = new DynamoDBQueryExpression<Customer>()
    .withRangeKeyCondition("Email",
        new Condition()
            .withComparisonOperator(ComparisonOperator.BEGINS_WITH)
            .withAttributeValueList(
                new AttributeValue().withS("my")));

mapper.query(Customer.class, emailBwQueryExpr);
```

在 V2 中，您可以使用建置器在請求物件上設定參數，而不是使用組態物件。例如：

```
QueryEnhancedRequest emailBw = QueryEnhancedRequest.builder()
    .queryConditional(QueryConditional
        .sortBeginsWith(kb -> kb
            .sortValue("my"))).build();

customerTable.query(emailBw);
```

## 有條件
<a name="dynamodb-mapping-conditionals"></a>

在 V2 中，條件式和篩選表達式會使用 物件來表示，該`Expression`物件會封裝條件以及名稱和篩選條件的映射。


| 使用案例 | 作業 | V1 | V2 | 
| --- | --- | --- | --- | 
| 預期的屬性條件 | save()， delete()， query()， scan() |  <pre>new DynamoDBSaveExpression()<br />  .withExpected(Collections.singletonMap(<br />      "otherAttribute", new ExpectedAttributeValue(false)))<br />  .withConditionalOperator(ConditionalOperator.AND);</pre>  | 已棄用；請ConditionExpression改用 。 | 
| 條件表達式 | delete() |  <pre>deleteExpression.setConditionExpression("zipcode = :zipcode")<br />deleteExpression.setExpressionAttributeValues(...)<br /></pre>  |  <pre>Expression conditionExpression =<br />    Expression.builder()<br />        .expression("#key = :value OR #key1 = :value1")<br />        .putExpressionName("#key", "attribute")<br />        .putExpressionName("#key1", "attribute3")<br />        .putExpressionValue(":value", AttributeValues.stringValue("wrong"))<br />        .putExpressionValue(":value1", AttributeValues.stringValue("three"))<br />        .build();<br /><br />DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()<br />         .conditionExpression(conditionExpression).build();</pre>  | 
| 篩選條件表達式 | query()， scan() |  <pre>scanExpression<br />  .withFilterExpression("#statename = :state")<br />  .withExpressionAttributeValues(attributeValueMapBuilder.build())<br />  .withExpressionAttributeNames(attributeNameMapBuilder.build())<br /></pre>  |  <pre>Map<String, AttributeValue> values = singletonMap(":key", stringValue("value"));<br />Expression filterExpression =<br />    Expression.builder()<br />        .expression("name = :key")<br />        .expressionValues(values)<br />        .build();<br />QueryEnhancedRequest request = QueryEnhancedRequest.builder()<br />    .filterExpression(filterExpression).build();<br /></pre>  | 
| 查詢的條件表達式 | query() |  <pre>queryExpression.withKeyConditionExpression()</pre>  |  <pre>QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b<br />                .partitionValue("movie01"));<br /><br />QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()<br />                .queryConditional(keyEqual)<br />                .build();</pre>  | 

## 類型轉換
<a name="dynamodb-mapping-type-conv"></a>

### 預設轉換器
<a name="dynamodb-mapping-type-conv-defaults"></a>

在 V2 中， SDK 為所有常見類型提供一組預設轉換器。您可以在整體供應商層級以及單一屬性變更類型轉換器。您可以在 [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html) API 參考中找到可用轉換器的清單。

### 設定屬性的自訂轉換器
<a name="dynamodb-mapping-type-conv-anno"></a>

在 V1 中，您可以使用 註釋 getter 方法`@DynamoDBTypeConverted`，以指定在 Java 屬性類型和 DynamoDB 屬性類型之間轉換的類別。例如，可在 Java `Currency`類型和 DynamoDB 字串之間`CurrencyFormatConverter`轉換的 可套用，如下列程式碼片段所示。

```
@DynamoDBTypeConverted(converter = CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

上一個程式碼片段的 V2 對等項目如下所示。

```
@DynamoDbConvertedBy(CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

**注意**  
在 V1 中，您可以將註釋套用至屬性本身 、類型或使用者定義的註釋，V2 僅支援將註釋套用至 getter。

### 新增類型轉換器工廠或供應商
<a name="dynamodb-mapping-type-conv-factory"></a>

在 V1 中，您可以提供自己的一組類型轉換器，或透過將類型轉換器工廠新增至組態來覆寫您關心的類型。類型轉換器工廠擴展 `DynamoDBTypeConverterFactory`，覆寫是透過取得預設設定的參考並將其擴展來完成。下列程式碼片段示範如何執行此操作。

```
DynamoDBTypeConverterFactory typeConverterFactory =
    DynamoDBTypeConverterFactory.standard().override()
        .with(String.class, CustomBoolean.class, new DynamoDBTypeConverter<String, CustomBoolean>() {
            @Override
            public String convert(CustomBoolean bool) {
                return String.valueOf(bool.getValue());
            }
            @Override
            public CustomBoolean unconvert(String string) {
                return new CustomBoolean(Boolean.valueOf(string));
            }}).build();
DynamoDBMapperConfig config =
    DynamoDBMapperConfig.builder()
        .withTypeConverterFactory(typeConverterFactory)
        .build();
DynamoDBMapper mapperWithTypeConverterFactory = new DynamoDBMapper(dynamo, config);
```

V2 透過`@DynamoDbBean`註釋提供類似的功能。您可以提供單一`AttributeConverterProvider`或一組已排序的 `AttributeConverterProvider`。請注意，如果您提供自己的屬性轉換器提供者鏈，您將覆寫預設轉換器提供者，且必須將其包含在鏈中，才能使用其屬性轉換器。

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {
  ...
}
```

本指南中[屬性轉換](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example)的 區段包含 V2 的完整範例。

# 適用於 Java 的 SDK 第 1 版和第 2 版之間的字串處理差異
<a name="dynamodb-migration-string-handling"></a>

將資料傳送至 DynamoDB 時，V1 和 V2 會以不同的方式處理空字串：
+ **V1**：將空字串轉換為 null 值，再傳送至 DynamoDB （無屬性）
+ **V2**：將空字串作為實際空字串值傳送至 DynamoDB

**重要**  
遷移至 V2 之後，如果您不希望在 DynamoDB 中存放空字串，則必須實作自訂轉換器。如果沒有自訂轉換器，V2 會將空字串儲存為 DynamoDB 項目中的實際空字串屬性，這與 V1 完全省略這些屬性的行為不同。

**Example 將空字串屬性轉換為 null 的 V2 自訂轉換器**  

```
/**
 * Custom converter that maintains V1 behavior by converting empty strings to null values
 * when writing to DynamoDB, ensuring compatibility with existing data. No attribute will be saved to DynamoDB.
 */
public class NullifyEmptyStringConverter implements AttributeConverter<String> {
    @Override
    public AttributeValue transformFrom(String value) {
        if (value == null || value.isEmpty()) {
            return AttributeValue.builder().nul(true).build();
        }
        return AttributeValue.builder().s(value).build();
    }

    @Override
    public String transformTo(AttributeValue attributeValue) {
        if (attributeValue.nul()) {
            return null;
        }
        return attributeValue.s();
    }

    @Override
    public EnhancedType<String> type() {
        return EnhancedType.of(String.class);
    }

    @Override
    public AttributeValueType attributeValueType() {
        return AttributeValueType.S;
    }
}

// V2 usage:
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(NullifyEmptyStringConverter.class)
    public String getName() {
        return name;
    }
}
```



# 適用於 Java 的 SDK 第 1 版和第 2 版之間的樂觀鎖定差異
<a name="dynamodb-migrate-optimstic-locking"></a>

V1 和 V2 都實作樂觀鎖定搭配屬性註釋，在您的 Bean 類別上標記一個屬性來存放版本號碼。


**樂觀鎖定行為的差異**  

|  | V1 | V2 | 
| --- | --- | --- | 
| Bean 類別註釋 | @DynamoDBVersionAttribute | @DynamoDbVersionAttribute （請注意，V2 使用小寫 "b") | 
| 初始儲存 | 版本編號屬性設定為 1。 |  使用 設定的版本屬性的起始值`@DynamoDbVersionAttribute(startAt = X)`。預設值為 0。  | 
| 更新 | 如果條件式檢查驗證要更新的物件版本編號符合資料庫中的編號，則版本編號屬性會遞增 1。 |  如果條件式檢查驗證要更新的物件版本編號符合資料庫中的編號，則版本編號屬性會遞增。 使用 設定`incrementBy`的選項遞增的版本編號屬性`@DynamoDbVersionAttribute(incrementBy = X)`。預設值為 1。  | 
| 刪除 | DynamoDBMapper 新增條件式檢查，確認要刪除之物件的版本編號符合資料庫中的版本編號。 |  V2 不會自動新增刪除操作的條件。如果您想要控制刪除行為，則必須手動新增條件表達式。 在下列範例中， `recordVersion`是 Bean 的版本屬性。 <pre>// 1. Read the item and get its current version.<br />Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build());<br />AttributeValue currentVersion = item.getRecordVersion();<br /><br />// 2. Create conditional delete with the `currentVersion` value.<br />DeleteItemEnhancedRequest deleteItemRequest =<br />    DeleteItemEnhancedRequest.builder()<br />       .key(KEY)<br />       .conditionExpression(Expression.builder()<br />           .expression("recordVersion = :current_version_value")<br />           .putExpressionValue(":current_version_value", currentVersion)<br />           .build()).build();<br /><br />customerTable.deleteItem(deleteItemRequest);</pre>  | 
| 具有條件檢查的交易寫入 | 您無法在 addConditionCheck方法@DynamoDBVersionAttribute中使用以 標註的 Bean 類別。 | 您可以在transactWriteItems請求的addConditionCheck建置器方法中使用具有 @DynamoDbVersionAttribute註釋的 Bean 類別。 | 
| 停用 | 透過將 DynamoDBMapperConfig.SaveBehavior列舉值從 變更為 UPDATE來停用樂觀鎖定CLOBBER。 |  請勿使用 `@DynamoDbVersionAttribute`註釋。  | 

# 適用於 Java 的 SDK 第 1 版和第 2 版之間的流暢設定器差異
<a name="dynamodb-migrate-fluent-setters"></a>

您可以在適用於 V1 POJOs 搭配流暢的設定器，以及搭配自 2.30.29 版以來的 V2。 DynamoDB 

例如，下列 POJO 會從 `setName`方法傳回`Customer`執行個體：

```
// V1

@DynamoDBTable(tableName ="Customer")
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){
     this.name = name;
     return this;
  }
}
```

不過，如果您使用 2.30.29 之前的 V2 版本， 會`setName`傳回`name`值為 的`Customer`執行個體`null`。

```
// V2 prior to version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Bug: returns this instance with a `name` value of `null`.
  }
}
```

```
// Available in V2 since version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Returns this instance for method chaining with the `name` value set.
  }
}
```