Lernen Sie die Grundlagen des DynamoDB Enhanced Client kennen API - AWS SDK for Java 2.x

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Lernen Sie die Grundlagen des DynamoDB Enhanced Client kennen API

In diesem Thema werden die grundlegenden Funktionen des DynamoDB Enhanced Client beschrieben API und er mit dem standardmäßigen DynamoDB-Client verglichen. API

Wenn Sie mit dem DynamoDB Enhanced Client noch nicht vertraut sind, empfehlen wir IhnenAPI, das Einführungstutorial zu lesen, um sich mit den grundlegenden Klassen vertraut zu machen.

DynamoDB-Elemente in Java

DynamoDB-Tabellen speichern Elemente. Abhängig von Ihrem Anwendungsfall können Elemente auf der Java-Seite die Form von statisch strukturierten Daten oder dynamisch erstellten Strukturen annehmen.

Wenn Ihr Anwendungsfall Elemente mit einem konsistenten Satz von Attributen erfordert, verwenden Sie annotierte Klassen oder verwenden Sie einen Builder, um die entsprechenden statisch typisierten Elemente zu generieren. TableSchema

Wenn Sie Elemente speichern müssen, die aus unterschiedlichen Strukturen bestehen, können Sie alternativ eine erstellen. DocumentTableSchema DocumentTableSchemaist Teil des erweiterten Dokuments API und benötigt nur einen statisch typisierten Primärschlüssel und funktioniert mit EnhancedDocument Instanzen, die die Datenelemente enthalten. Das erweiterte Dokument API wird in einem anderen Thema behandelt.

Attributtypen für Datenmodellklassen

Obwohl DynamoDB im Vergleich zum Rich-Type-System von Java eine geringe Anzahl von Attributtypen unterstützt, API bietet der DynamoDB Enhanced Client Mechanismen zum Konvertieren von Mitgliedern einer Java-Klasse in und aus DynamoDB-Attributtypen.

Bei den Attributtypen (Eigenschaften) Ihrer Java-Datenklassen sollte es sich um Objekttypen und nicht um Primitive handeln. Verwenden Sie beispielsweise immer Datentypen Long und Integer Objekte, nicht long int Primitive.

Standardmäßig API unterstützt der DynamoDB Enhanced Client Attributkonverter für eine Vielzahl von Typen, wie Integer BigDecimal, String und Instant. Die Liste wird in den bekannten Implementierungsklassen der AttributeConverter Schnittstelle angezeigt. Die Liste enthält viele Typen und Sammlungen wie Karten, Listen und Sets.

Um die Daten für einen Attributtyp zu speichern, der standardmäßig nicht unterstützt wird oder nicht der JavaBean Konvention entspricht, können Sie eine benutzerdefinierte AttributeConverter Implementierung für die Konvertierung schreiben. Ein Beispiel finden Sie im Abschnitt zur Attributkonvertierung.

Um die Daten für einen Attributtyp zu speichern, dessen Klasse der Java-Beans-Spezifikation (oder einer unveränderlichen Datenklasse) entspricht, können Sie zwei Ansätze wählen.

  • Wenn Sie Zugriff auf die Quelldatei haben, können Sie die Klasse mit @DynamoDbBean (oder) annotieren. @DynamoDbImmutable Der Abschnitt, in dem verschachtelte Attribute behandelt werden, zeigt Beispiele für die Verwendung von Klassen mit Anmerkungen.

  • Wenn Sie keinen Zugriff auf die Quelldatei der JavaBean Datenklasse für das Attribut haben (oder Sie die Quelldatei einer Klasse, auf die Sie Zugriff haben, nicht mit Anmerkungen versehen möchten), können Sie den Builder-Ansatz verwenden. Dadurch wird ein Tabellenschema erstellt, ohne die Schlüssel zu definieren. Anschließend können Sie dieses Tabellenschema in einem anderen Tabellenschema verschachteln, um die Zuordnung durchzuführen. Der Abschnitt mit verschachtelten Attributen enthält ein Beispiel, das die Verwendung verschachtelter Schemas zeigt.

Null-Werte

Wenn Sie die putItem Methode verwenden, nimmt der erweiterte Client keine nullwertigen Attribute eines zugewiesenen Datenobjekts in die Anforderung an DynamoDB auf.

SDKDas Standardverhalten von für updateItem Anfragen entfernt Attribute aus dem Element in DynamoDB, die in dem Objekt, das Sie in der Methode einreichen, auf Null gesetzt sind. updateItem Wenn Sie beabsichtigen, einige Attributwerte zu aktualisieren und die anderen unverändert zu lassen, haben Sie zwei Möglichkeiten.

  • Rufen Sie das Element (mithilfe vongetItem) ab, bevor Sie Änderungen an den Werten vornehmen. Mit diesem Ansatz SDK sendet der alle aktualisierten und alten Werte an DynamoDB.

  • Verwenden Sie entweder IgnoreNullsMode.SCALAR_ONLY oder, IgnoreNullsMode.MAPS_ONLY wenn Sie die Anforderung erstellen, um das Element zu aktualisieren. Beide Modi ignorieren nullwertige Eigenschaften im Objekt, die skalare Attribute in DynamoDB darstellen. Das Aktualisieren Sie Elemente, die komplexe Typen enthalten Thema in diesem Handbuch enthält weitere Informationen zu den IgnoreNullsMode Werten und zur Arbeit mit komplexen Typen.

Das folgende ignoreNullsMode() Beispiel zeigt die updateItem() Methode.

public static void updateItemNullsExample() { Customer customer = new Customer(); customer.setCustName("CustomerName"); customer.setEmail("email"); customer.setId("1"); customer.setRegistrationDate(Instant.now()); logger.info("Original customer: {}", customer); // Put item with values for all attributes. try { customerAsyncDynamoDbTable.putItem(customer).join(); } catch (RuntimeException rte) { logger.error("A exception occurred during putItem: {}", rte.getCause().getMessage(), rte); return; } // Create a Customer instance with the same 'id' and 'email' values, but a different 'name' value. // Do not set the 'registrationDate' attribute. Customer customerForUpdate = new Customer(); customerForUpdate.setCustName("NewName"); customerForUpdate.setEmail("email"); customerForUpdate.setId("1"); // Update item without setting the 'registrationDate' property and set IgnoreNullsMode to SCALAR_ONLY. try { Customer updatedWithNullsIgnored = customerAsyncDynamoDbTable.updateItem(b -> b .item(customerForUpdate) .ignoreNullsMode(IgnoreNullsMode.SCALAR_ONLY)) .join(); logger.info("Customer updated with nulls ignored: {}", updatedWithNullsIgnored.toString()); } catch (RuntimeException rte) { logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte); return; } // Update item without setting the registrationDate attribute and not setting ignoreNulls to true. try { Customer updatedWithNullsUsed = customerAsyncDynamoDbTable.updateItem(customerForUpdate) .join(); logger.info("Customer updated with nulls used: {}", updatedWithNullsUsed.toString()); } catch (RuntimeException rte) { logger.error("An exception occurred during updateItem: {}", rte.getCause().getMessage(), rte); } } // Logged lines. Original customer: Customer [id=1, name=CustomerName, email=email, regDate=2024-10-11T14:12:30.222858Z] Customer updated with nulls ignored: Customer [id=1, name=NewName, email=email, regDate=2024-10-11T14:12:30.222858Z] Customer updated with nulls used: Customer [id=1, name=NewName, email=email, regDate=null]

Grundlegende Methoden des DynamoDB Enhanced Client

Die grundlegenden Methoden des erweiterten Clients sind den DynamoDB-Dienstoperationen zugeordnet, nach denen sie benannt sind. Die folgenden Beispiele zeigen die einfachste Variante der einzelnen Methoden. Sie können jede Methode anpassen, indem Sie ein erweitertes Anforderungsobjekt übergeben. Verbesserte Anforderungsobjekte bieten die meisten Funktionen, die im Standard-DynamoDB-Client verfügbar sind. Sie sind in der Referenz vollständig dokumentiert. AWS SDK for Java 2.x API

Das Beispiel verwendet das zuvor Customer-Klasse Gezeigte.

// CreateTable customerTable.createTable(); // GetItem Customer customer = customerTable.getItem(Key.builder().partitionValue("a123").build()); // UpdateItem Customer updatedCustomer = customerTable.updateItem(customer); // PutItem customerTable.putItem(customer); // DeleteItem Customer deletedCustomer = customerTable.deleteItem(Key.builder().partitionValue("a123").sortValue(456).build()); // Query PageIterable<Customer> customers = customerTable.query(keyEqualTo(k -> k.partitionValue("a123"))); // Scan PageIterable<Customer> customers = customerTable.scan(); // BatchGetItem BatchGetResultPageIterable batchResults = enhancedClient.batchGetItem(r -> r.addReadBatch(ReadBatch.builder(Customer.class) .mappedTableResource(customerTable) .addGetItem(key1) .addGetItem(key2) .addGetItem(key3) .build())); // BatchWriteItem batchResults = enhancedClient.batchWriteItem(r -> r.addWriteBatch(WriteBatch.builder(Customer.class) .mappedTableResource(customerTable) .addPutItem(customer) .addDeleteItem(key1) .addDeleteItem(key1) .build())); // TransactGetItems transactResults = enhancedClient.transactGetItems(r -> r.addGetItem(customerTable, key1) .addGetItem(customerTable, key2)); // TransactWriteItems enhancedClient.transactWriteItems(r -> r.addConditionCheck(customerTable, i -> i.key(orderKey) .conditionExpression(conditionExpression)) .addUpdateItem(customerTable, customer) .addDeleteItem(customerTable, key));

DynamoDB Enhanced Client mit dem Standard-DynamoDB-Client vergleichen

Sowohl der DynamoDB-Client APIs — der Standard - als auch der erweiterte — ermöglichen es Ihnen, mit DynamoDB-Tabellen zu arbeiten, um Operationen auf CRUD Datenebene durchzuführen (Erstellen, Lesen, Aktualisieren und Löschen). Der Unterschied zwischen den Clients APIs besteht darin, wie das bewerkstelligt wird. Mit dem Standard-Client arbeiten Sie direkt mit Datenattributen auf niedriger Ebene. Der erweiterte Client API verwendet vertraute Java-Klassen und ordnet dem API Low-Level-Hintergrund zu.

Während beide Clients Operationen auf Datenebene APIs unterstützen, unterstützt der standardmäßige DynamoDB-Client auch Operationen auf Ressourcenebene. Operationen auf Ressourcenebene verwalten die Datenbank, z. B. das Erstellen von Backups, das Auflisten von Tabellen und das Aktualisieren von Tabellen. Der erweiterte Client API unterstützt eine bestimmte Anzahl von Vorgängen auf Ressourcenebene, z. B. das Erstellen, Beschreiben und Löschen von Tabellen.

Um die unterschiedlichen Ansätze der beiden Clients zu veranschaulichenAPIs, zeigen die folgenden Codebeispiele die Erstellung derselben ProductCatalog Tabelle mit dem Standard-Client und dem erweiterten Client.

Vergleichen: Erstellen Sie eine Tabelle mit dem standardmäßigen DynamoDB-Client

DependencyFactory.dynamoDbClient().createTable(builder -> builder .tableName(TABLE_NAME) .attributeDefinitions( b -> b.attributeName("id").attributeType(ScalarAttributeType.N), b -> b.attributeName("title").attributeType(ScalarAttributeType.S), b -> b.attributeName("isbn").attributeType(ScalarAttributeType.S) ) .keySchema( builder1 -> builder1.attributeName("id").keyType(KeyType.HASH), builder2 -> builder2.attributeName("title").keyType(KeyType.RANGE) ) .globalSecondaryIndexes(builder3 -> builder3 .indexName("products_by_isbn") .keySchema(builder2 -> builder2 .attributeName("isbn").keyType(KeyType.HASH)) .projection(builder2 -> builder2 .projectionType(ProjectionType.INCLUDE) .nonKeyAttributes("price", "authors")) .provisionedThroughput(builder4 -> builder4 .writeCapacityUnits(5L).readCapacityUnits(5L)) ) .provisionedThroughput(builder1 -> builder1 .readCapacityUnits(5L).writeCapacityUnits(5L)) );

Vergleichen: Erstellen Sie eine Tabelle mit dem DynamoDB Enhanced Client

DynamoDbEnhancedClient enhancedClient = DependencyFactory.enhancedClient(); productCatalog = enhancedClient.table(TABLE_NAME, TableSchema.fromImmutableClass(ProductCatalog.class)); productCatalog.createTable(b -> b .provisionedThroughput(b1 -> b1.readCapacityUnits(5L).writeCapacityUnits(5L)) .globalSecondaryIndices(b2 -> b2.indexName("products_by_isbn") .projection(b4 -> b4 .projectionType(ProjectionType.INCLUDE) .nonKeyAttributes("price", "authors")) .provisionedThroughput(b3 -> b3.writeCapacityUnits(5L).readCapacityUnits(5L)) ) );

Der erweiterte Client verwendet die folgende Datenklasse mit Anmerkungen. Der DynamoDB Enhanced Client ordnet Java-Datentypen DynamoDB-Datentypen zu und sorgt so für weniger ausführlichen Code, der leichter nachzuvollziehen ist. ProductCatalogist ein Beispiel für die Verwendung einer unveränderlichen Klasse mit dem DynamoDB Enhanced Client. Die Verwendung unveränderlicher Klassen für zugeordnete Datenklassen wird später in diesem Thema erörtert.

package org.example.tests.model; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbIgnore; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbImmutable; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey; import java.math.BigDecimal; import java.util.Objects; import java.util.Set; @DynamoDbImmutable(builder = ProductCatalog.Builder.class) public class ProductCatalog implements Comparable<ProductCatalog> { private Integer id; private String title; private String isbn; private Set<String> authors; private BigDecimal price; private ProductCatalog(Builder builder){ this.authors = builder.authors; this.id = builder.id; this.isbn = builder.isbn; this.price = builder.price; this.title = builder.title; } public static Builder builder(){ return new Builder(); } @DynamoDbPartitionKey public Integer id() { return id; } @DynamoDbSortKey public String title() { return title; } @DynamoDbSecondaryPartitionKey(indexNames = "products_by_isbn") public String isbn() { return isbn; } public Set<String> authors() { return authors; } public BigDecimal price() { return price; } public static final class Builder { private Integer id; private String title; private String isbn; private Set<String> authors; private BigDecimal price; private Builder(){} public Builder id(Integer id) { this.id = id; return this; } public Builder title(String title) { this.title = title; return this; } public Builder isbn(String ISBN) { this.isbn = ISBN; return this; } public Builder authors(Set<String> authors) { this.authors = authors; return this; } public Builder price(BigDecimal price) { this.price = price; return this; } public ProductCatalog build() { return new ProductCatalog(this); } } @Override public String toString() { final StringBuffer sb = new StringBuffer("ProductCatalog{"); sb.append("id=").append(id); sb.append(", title='").append(title).append('\''); sb.append(", isbn='").append(isbn).append('\''); sb.append(", authors=").append(authors); sb.append(", price=").append(price); sb.append('}'); return sb.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ProductCatalog that = (ProductCatalog) o; return id.equals(that.id) && title.equals(that.title) && Objects.equals(isbn, that.isbn) && Objects.equals(authors, that.authors) && Objects.equals(price, that.price); } @Override public int hashCode() { return Objects.hash(id, title, isbn, authors, price); } @Override @DynamoDbIgnore public int compareTo(ProductCatalog other) { if (this.id.compareTo(other.id) != 0){ return this.id.compareTo(other.id); } else { return this.title.compareTo(other.title); } } }

Die folgenden beiden Codebeispiele für Batch-Schreibvorgänge veranschaulichen die Ausführlichkeit und die mangelnde Typsicherheit bei der Verwendung des Standardclients im Gegensatz zum erweiterten Client.

public static void batchWriteStandard(DynamoDbClient dynamoDbClient, String tableName) { Map<String, AttributeValue> catalogItem = Map.of( "authors", AttributeValue.builder().ss("a", "b").build(), "id", AttributeValue.builder().n("1").build(), "isbn", AttributeValue.builder().s("1-565-85698").build(), "title", AttributeValue.builder().s("Title 1").build(), "price", AttributeValue.builder().n("52.13").build()); Map<String, AttributeValue> catalogItem2 = Map.of( "authors", AttributeValue.builder().ss("a", "b", "c").build(), "id", AttributeValue.builder().n("2").build(), "isbn", AttributeValue.builder().s("1-208-98073").build(), "title", AttributeValue.builder().s("Title 2").build(), "price", AttributeValue.builder().n("21.99").build()); Map<String, AttributeValue> catalogItem3 = Map.of( "authors", AttributeValue.builder().ss("g", "k", "c").build(), "id", AttributeValue.builder().n("3").build(), "isbn", AttributeValue.builder().s("7-236-98618").build(), "title", AttributeValue.builder().s("Title 3").build(), "price", AttributeValue.builder().n("42.00").build()); Set<WriteRequest> writeRequests = Set.of( WriteRequest.builder().putRequest(b -> b.item(catalogItem)).build(), WriteRequest.builder().putRequest(b -> b.item(catalogItem2)).build(), WriteRequest.builder().putRequest(b -> b.item(catalogItem3)).build()); Map<String, Set<WriteRequest>> productCatalogItems = Map.of( "ProductCatalog", writeRequests); BatchWriteItemResponse response = dynamoDbClient.batchWriteItem(b -> b.requestItems(productCatalogItems)); logger.info("Unprocessed items: " + response.unprocessedItems().size()); }
public static void batchWriteEnhanced(DynamoDbTable<ProductCatalog> productCatalog) { ProductCatalog prod = ProductCatalog.builder() .id(1) .isbn("1-565-85698") .authors(new HashSet<>(Arrays.asList("a", "b"))) .price(BigDecimal.valueOf(52.13)) .title("Title 1") .build(); ProductCatalog prod2 = ProductCatalog.builder() .id(2) .isbn("1-208-98073") .authors(new HashSet<>(Arrays.asList("a", "b", "c"))) .price(BigDecimal.valueOf(21.99)) .title("Title 2") .build(); ProductCatalog prod3 = ProductCatalog.builder() .id(3) .isbn("7-236-98618") .authors(new HashSet<>(Arrays.asList("g", "k", "c"))) .price(BigDecimal.valueOf(42.00)) .title("Title 3") .build(); BatchWriteResult batchWriteResult = DependencyFactory.enhancedClient() .batchWriteItem(b -> b.writeBatches( WriteBatch.builder(ProductCatalog.class) .mappedTableResource(productCatalog) .addPutItem(prod).addPutItem(prod2).addPutItem(prod3) .build() )); logger.info("Unprocessed items: " + batchWriteResult.unprocessedPutItemsForTable(productCatalog).size()); }