適用於 Java 的 SDK 第 1 版和第 2 版之間的 DynamoDB 映射 APIs 變更 - AWS SDK for Java 2.x

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

適用於 Java 的 SDK 第 1 版和第 2 版之間的 DynamoDB 映射 APIs 變更

建立用戶端

使用案例 V1 V2

正常執行個體化

AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard() .withCredentials(credentialsProvider) .withRegion(Regions.US_EAST_1) .build(); DynamoDBMapper mapper = new DynamoDBMapper(standardClient);
DynamoDbClient standardClient = DynamoDbClient.builder() .credentialsProvider(ProfileCredentialsProvider.create()) .region(Region.US_EAST_1) .build(); DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(standardClient) .build();

最小執行個體化

AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard(); DynamoDBMapper mapper = new DynamoDBMapper(standardClient);
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();

使用屬性轉換器*

DynamoDBMapper mapper = new DynamoDBMapper(standardClient, attributeTransformerInstance);
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(standardClient) .extensions(extensionAInstance, extensionBInstance) .build();

*V2 中的延伸大約對應至 V1 中的屬性轉換器。使用擴充功能自訂 DynamoDB 增強型用戶端操作 本節包含 V2 中延伸模組的詳細資訊。

建立對 DynamoDB 資料表/索引的映射

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

使用案例 V1 V2

將 Java POJO 類別映射至 DynamoDB 資料表

@DynamoDBTable(tableName ="Customer") public class Customer { ... }
DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));

映射至 DynamoDB 次要索引

  1. 定義代表索引的 POJO 類別。

    • 使用@DynamoDBTable提供具有索引之資料表名稱的 來註釋類別。

    • 使用 @DynamoDBIndexHashKey和選用的 註釋屬性@DynamoDBIndexRangeKey

  2. 建立查詢表達式。

  3. 使用代表索引的 POJO 類別參考進行查詢。例如

    mapper.query(IdEmailIndex.class, queryExpression)

    其中 IdEmailIndex是索引的映射類別。

DynamoDB 開發人員指南中討論 V1 query方法的 區段會顯示完整的範例。

  1. 使用 @DynamoDbSecondaryPartitionKey(適用於 GSI) 和 @DynamoDbSecondarySortKey(適用於 和 GSI 或 LSI) 註釋 POJO 類別的屬性。例如

    @DynamoDbSecondarySortKey(indexNames = "IdEmailIndex") public String getEmail() { return this.email; }
  2. 擷取索引的參考。例如

    DynamoDbIndex<Customer> customerIndex = customerTable.index("IdEmailIndex");
  3. 查詢索引。

本指南中的 使用次要索引區段提供更多資訊。

資料表操作

本節說明大多數標準使用案例在 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 操作:PutItemUpdateItem

mapper.save(item) mapper.save(item, config) mapper.save(item, saveExpression, config)

在 V1 中, DynamoDBMapperConfig.SaveBehavior和 註釋會決定要呼叫哪個低階 DynamoDB 方法。一般而言, UpdateItem 會在使用 SaveBehavior.CLOBBER和 時呼叫 SaveBehavior.PUT。自動產生的金鑰是特殊的使用案例,偶爾同時使用 UpdateItem PutItem和 。

table.putItem(putItemRequest) table.putItem(item) table.putItemWithResponse(item) //Returns metadata. updateItem(updateItemRequest) table.updateItem(item) table.updateItemWithResponse(item) //Returns metadata.

將項目從 DynamoDB 資料表讀取至 Java POJO

DynamoDB 操作: GetItem

mapper.load(item) mapper.load(item, config)
table.getItem(getItemRequest) table.getItem(item) table.getItem(key) table.getItemWithResponse(key) //Returns POJO with metadata.

從 DynamoDB 資料表刪除項目

DynamoDB 操作: DeleteItem

mapper.delete(item, deleteExpression, config)
table.deleteItem(deleteItemRequest) table.deleteItem(item) table.deleteItem(key)

查詢 DynamoDB 資料表或次要索引並傳回分頁清單

DynamoDB 操作: Query

mapper.query(Customer.class, queryExpression) mapper.query(Customer.class, queryExpression, mapperConfig)
table.query(queryRequest) table.query(queryConditional)

將傳回的 PageIterable.stream()(延遲載入) 用於同步回應和非PagePublisher.subscribe()同步回應

查詢 DynamoDB 資料表或次要索引並傳回清單

DynamoDB 操作: Query

mapper.queryPage(Customer.class, queryExpression) mapper.queryPage(Customer.class, queryExpression, mapperConfig)
table.query(queryRequest) table.query(queryConditional)

將傳回的 PageIterable.items()(延遲載入) 用於同步回應和非PagePublisher.items.subscribe()同步回應

掃描 DynamoDB 資料表或次要索引並傳回分頁清單

DynamoDB 操作: Scan

mapper.scan(Customer.class, scanExpression) mapper.scan(Customer.class, scanExpression, mapperConfig)
table.scan() table.scan(scanRequest)

將傳回的 PageIterable.stream()(延遲載入) 用於同步回應和非PagePublisher.subscribe()同步回應

掃描 DynamoDB 資料表或次要索引並傳回清單

DynamoDB 操作: Scan

mapper.scanPage(Customer.class, scanExpression) mapper.scanPage(Customer.class, scanExpression, mapperConfig)
table.scan() table.scan(scanRequest)

將傳回的 PageIterable.items()(延遲載入) 用於同步回應和非PagePublisher.items.subscribe()同步回應

從批次中的多個資料表讀取多個項目

DynamoDB 操作: BatchGetItem

mapper.batchLoad(Arrays.asList(customer1, customer2, book1)) mapper.batchLoad(itemsToGet) // itemsToGet: Map<Class<?>, List<KeyPair>>
enhancedClient.batchGetItem(batchGetItemRequest) enhancedClient.batchGetItem(r -> r.readBatches( ReadBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addGetItem(i -> i.key(k -> k.partitionValue(0))) .build(), ReadBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addGetItem(i -> i.key(k -> k.partitionValue(0))) .build())) // Iterate over pages with lazy loading or over all items from the same table.

將多個項目寫入批次中的多個資料表

DynamoDB 操作: BatchWriteItem

mapper.batchSave(Arrays.asList(customer1, customer2, book1))
enhancedClient.batchWriteItem(batchWriteItemRequest) enhancedClient.batchWriteItem(r -> r.writeBatches( WriteBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addPutItem(item1) .build(), WriteBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addPutItem(item2) .build()))

從批次中的多個資料表刪除多個項目

DynamoDB 操作: BatchWriteItem

mapper.batchDelete(Arrays.asList(customer1, customer2, book1))
enhancedClient.batchWriteItem(r -> r.writeBatches( WriteBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addDeleteItem(item1key) .build(), WriteBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addDeleteItem(item2key) .build()))

寫入/刪除批次中的多個項目

DynamoDB 操作: BatchWriteItem

mapper.batchWrite(Arrays.asList(customer1, book1), Arrays.asList(customer2))
enhancedClient.batchWriteItem(r -> r.writeBatches( WriteBatch.builder(Record1.class) .mappedTableResource(mappedTable1) .addPutItem(item1) .build(), WriteBatch.builder(Record2.class) .mappedTableResource(mappedTable2) .addDeleteItem(item2key) .build()))

執行交易寫入

DynamoDB 操作: TransactWriteItems

mapper.transactionWrite(transactionWriteRequest)
enhancedClient.transactWriteItems(transasctWriteItemsRequest)

執行交易讀取

DynamoDB 操作: TransactGetItems

mapper.transactionLoad(transactionLoadRequest)
enhancedClient.transactGetItems(transactGetItemsRequest)

取得查詢相符項目的計數

DynamoDB 操作:Query使用 Select.COUNT

mapper.count(Customer.class, queryExpression)
// Get the count from query results. PageIterable<Customer> pageIterable = customerTable.query(QueryEnhancedRequest.builder() .queryConditional(queryConditional) .select(Select.COUNT) .build()); Iterator<Page<Customer>> iterator = pageIterable.iterator(); Page<Customer> page = iterator.next(); int count = page.count(); // For a more concise approach, you can chain the method calls: int count = customerTable.query(QueryEnhancedRequest.builder() .queryConditional(queryConditional) .select(Select.COUNT) .build()) .iterator().next().count();

取得掃描相符項目的計數

DynamoDB 操作:Scan使用 Select.COUNT

mapper.count(Customer.class, scanExpression)
// Get the count from scan results. PageIterable<Customer> pageIterable = customerTable.scan(ScanEnhancedRequest.builder() .filterExpression(filterExpression) .select(Select.COUNT) .build()); Iterator<Page<Customer>> iterator = pageIterable.iterator(); Page<Customer> page = iterator.next(); int count = page.count(); // For a more concise approach, you can chain the method calls: int count = customerTable.scan(ScanEnhancedRequest.builder() .filterExpression(filterExpression) .select(Select.COUNT) .build()) .iterator().next().count();

在對應至 POJO 類別的 DynamoDB 中建立資料表

DynamoDB 操作: CreateTable

mapper.generateCreateTableRequest(Customer.class)

先前的陳述式會產生低階建立資料表請求;使用者必須在 DynamoDB 用戶端createTable上呼叫 。

table.createTable(createTableRequest) table.createTable(r -> r.provisionedThroughput(defaultThroughput()) .globalSecondaryIndices( EnhancedGlobalSecondaryIndex.builder() .indexName("gsi_1") .projection(p -> p.projectionType(ProjectionType.ALL)) .provisionedThroughput(defaultThroughput()) .build()));

在 DynamoDB 中執行平行掃描

DynamoDB 操作:Scan使用 SegmentTotalSegments 參數

mapper.parallelScan(Customer.class, scanExpression, numTotalSegments)

使用者需要處理scan每個區段的工作者執行緒和呼叫:

table.scan(r -> r.segment(0).totalSegments(5))

將 Amazon S3 與 DynamoDB 整合,以存放智慧型 S3 連結

mapper.createS3Link(bucket, key) mapper.getS3ClientCache()

不支援,因為它會耦合 Amazon S3 和 DynamoDB。

映射類別和屬性

在 V1 和 V2 中,您可以使用 Bean 樣式註釋將類別映射至資料表。V2 也提供其他方法來定義特定使用案例的結構描述,例如使用不可變類別。

Bean 註釋

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

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

使用案例 V1 V2
將類別映射至資料表
@DynamoDBTable (tableName ="CustomerTable")
@DynamoDbBean @DynamoDbBean(converterProviders = {...})
呼叫 DynamoDbEnhancedClient#table()方法時會定義資料表名稱。
將類別成員指定為資料表屬性
@DynamoDBAttribute(attributeName = "customerName")
@DynamoDbAttribute("customerName")
指定類別成員是雜湊/分割區索引鍵
@DynamoDBHashKey
@DynamoDbPartitionKey
指定類別成員是範圍/排序索引鍵
@DynamoDBRangeKey
@DynamoDbSortKey
指定類別成員是次要索引雜湊/分割區索引鍵
@DynamoDBIndexHashKey
@DynamoDbSecondaryPartitionKey
指定類別成員是次要索引範圍/排序索引鍵
@DynamoDBIndexRangeKey
@DynamoDbSecondarySortKey
映射至資料表時忽略此類別成員
@DynamoDBIgnore
@DynamoDbIgnore
將類別成員指定為自動產生的 UUID 金鑰屬性
@DynamoDBAutoGeneratedKey
@DynamoDbAutoGeneratedUuid

根據預設,不會載入提供此項目的延伸模組;您必須將延伸模組新增至用戶端建置器。

將類別成員指定為自動產生的時間戳記屬性
@DynamoDBAutoGeneratedTimestamp
@DynamoDbAutoGeneratedTimestampAttribute

根據預設,不會載入提供此項目的延伸模組;您必須將延伸模組新增至用戶端建置器。

將類別成員指定為自動遞增版本屬性
@DynamoDBVersionAttribute
@DynamoDbVersionAttribute

提供此功能的延伸模組會自動載入。

將類別成員指定為需要自訂轉換
@DynamoDBTypeConverted
@DynamoDbConvertedBy
指定要儲存為不同屬性類型的類別成員
@DynamoDBTyped(<DynamoDBAttributeType>)

使用 AttributeConverter實作。V2 為常見的 Java 類型提供許多內建轉換器。您也可以實作自己的自訂 AttributeConverterAttributeConverterProvider。請參閱本指南控制屬性轉換中的 。

指定可序列化為 DynamoDB 文件 (JSON 樣式文件) 或子文件的類別
@DynamoDBDocument
使用增強型文件 API。請參閱下列資源:

V2 其他註釋

使用案例 V1 V2
如果 Java 值為 null,則指定不將類別成員儲存為 NULL 屬性 N/A
@DynamoDbIgnoreNulls
如果所有屬性都是 null,請將類別成員指定為空白物件 N/A
@DynamoDbPreserveEmptyObject
指定類別成員的特殊更新動作 N/A
@DynamoDbUpdateBehavior
指定不可變類別 N/A
@DynamoDbImmutable
將類別成員指定為自動遞增的計數器屬性 N/A
@DynamoDbAtomicCounter

自動載入提供此功能的延伸模組。

組態

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

使用案例 V1 V1 中的預設值 V2
DynamoDBMapperConfig.builder()
批次載入/寫入重試策略
.withBatchLoadRetryStrategy(loadRetryStrategy)
.withBatchWriteRetryStrategy(writeRetryStrategy)
重試失敗的項目 在基礎 上設定重試策略DynamoDBClient。請參閱本指南在 中設定重試行為 AWS SDK for Java 2.x中的 。
一致的讀取
.withConsistentReads(CONSISTENT)
EVENTUAL 根據預設,讀取操作的一致性讀取為 false。在請求物件.consistentRead(true)上使用 覆寫 。
具有 marshallers/unmarshallers 集的轉換結構描述
.withConversionSchema(conversionSchema)

靜態實作提供與舊版的回溯相容性。

V2_COMPATIBLE 不適用。這是舊版功能,指 DynamoDB (V1) 儲存資料類型的最早版本,而且此行為不會保留在增強型用戶端中。DynamoDB V1 中的行為範例是將布林值儲存為數字而非布林值。
資料表名稱
.withObjectTableNameResolver() .withTableNameOverride() .withTableNameResolver()

靜態實作提供與舊版的回溯相容性

使用 類別的註釋或猜測

呼叫 DynamoDbEnhancedClient#table()方法時會定義資料表名稱。

分頁載入策略
.withPaginationLoadingStrategy(strategy)

選項為:LAZY_EAGER_LOADINGLOADINGITERATION_ONLY

LAZY_LOADING
  • 預設值僅為反覆運算。不支援其他 V1 選項。

  • 您可以使用下列項目在 V2 中實作等同急迫載入:

    List<Customer> allItems = customerTable.scan().items().stream().collect(Collectors.toList());
  • 對於延遲載入,您必須為存取的項目實作自己的快取邏輯。

請求指標集合
.withRequestMetricCollector(collector)
null 在建置標準 DynamoDB 用戶端metricPublisher()ClientOverrideConfiguration時使用 。
儲存行為
.withSaveBehavior(SaveBehavior.CLOBBER)

選項為 UPDATECLOBBERAPPEND_SETPUTUPDATE_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:不支援

類型轉換器工廠
.withTypeConverterFactory(typeConverterFactory)
標準類型轉換器

使用 在 Bean 上設定

@DynamoDbBean(converterProviders = {ConverterProvider.class, DefaultAttributeConverterProvider.class})

每個操作組態

在 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);

有條件

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

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

類型轉換

預設轉換器

在 V2 中, SDK 為所有常見類型提供一組預設轉換器。您可以在整體供應商層級以及單一屬性變更類型轉換器。您可以在 AttributeConverter API 參考中找到可用轉換器的清單。

設定屬性的自訂轉換器

在 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。

新增類型轉換器工廠或供應商

在 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 { ... }

本指南中屬性轉換的 區段包含 V2 的完整範例。