Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.
Aprenda los conceptos básicos de la API de cliente mejorado de DynamoDB
Este tema trata las características básicas de la API de cliente mejorado de DynamoDB y la compara con la API de cliente de DynamoDB estándar
Si es la primera vez que utiliza la API de cliente mejorado de DynamoDB, le recomendamos que consulte el tutorial introductorio para familiarizarse con las clases fundamentales.
Elementos de DynamoDB en Java
Las tablas de DynamoDB almacenan elementos. Según el caso práctico, los elementos del lado de Java pueden adoptar la forma de datos estructurados de forma estática o estructuras creadas dinámicamente.
Si su caso requiere elementos con un conjunto coherente de atributos, utilice clases anotadas o un constructor para generar los tipos estáticos adecuados de TableSchema
.
Alternativamente, si necesita almacenar elementos que consten de estructuras variables, cree un DocumentTableSchema
. DocumentTableSchema
forma parte de la API de documento mejorada y solo requiere una clave principal de tipo estático y funciona con instancias EnhancedDocument
para contener los elementos de datos. La API de documentos mejorada se trata en otro tema.
Tipos de atributos para clases de modelos de datos
Si bien DynamoDB admite un número menor de tipos de atributos en comparación con el sistema de tipos enriquecidos de Java, la API de cliente mejorado de DynamoDB proporciona mecanismos para convertir los miembros de una clase de Java a y desde tipos de atributos de DynamoDB.
Los tipos de atributos (propiedades) de las clases de datos de Java deben ser tipos de objetos, no primitivos. Por ejemplo, utilice siempre tipos Long
de datos tipo Integer
objeto, no long
int
primitivos.
De forma predeterminada, la API de cliente mejorada de DynamoDB admite convertidores de atributos para una gran cantidad de tipos, como
Para almacenar los datos de un tipo de atributo que no se admite de forma predeterminada o que no se ajusta a la JavaBean convención, puede escribir una AttributeConverter
implementación personalizada para realizar la conversión. Consulte la sección sobre conversión de atributos para ver un ejemplo.
Para almacenar los datos de un tipo de atributo cuya clase cumpla con la especificación de beans de Java (o una clase de datos inmutable), puede adoptar dos enfoques.
-
Si tiene acceso al archivo fuente, puede anotar la clase con
@DynamoDbBean
(o@DynamoDbImmutable
). La sección que analiza los atributos anidados muestra ejemplos del uso de clases anotadas.
-
Si no tiene acceso al archivo de origen de la clase de JavaBean datos del atributo (o no quiere hacer anotaciones en el archivo de origen de una clase a la que sí tiene acceso), puede utilizar el enfoque de creación. Esto crea un esquema de tabla sin definir las claves. A continuación, puede anidar este esquema de tabla dentro de otro esquema de tabla para realizar el mapeo. La sección de atributos anidados contiene un ejemplo que muestra el uso de esquemas anidados.
Valores nulos
Al utilizar la API de putItem
, el cliente mejorado no incluye los atributos con valores nulos de un objeto de datos mapeado en la solicitud a DynamoDB.
En el caso de las solicitudes de updateItem
, los atributos con valores nulos se eliminan del elemento de la base de datos. Si va a actualizar algunos valores de atributo y mantener los demás sin cambios, copie los valores de otros atributos que no se deben cambiar o utilice el método ignoreNull ()
El siguiente ejemplo demuestra ignoreNulls()
para el método the
updateItem()
.
public void updateItemNullsExample(){ Customer customer = new Customer(); customer.setCustName("CustName"); customer.setEmail("email"); customer.setId("1"); customer.setRegistrationDate(Instant.now()); // Put item with values for all attributes. customerDynamoDbTable.putItem(customer); // Create a Customer instance with the same id value, but a different name value. // Do not set the 'registrationDate' attribute. Customer custForUpdate = new Customer(); custForUpdate.setCustName("NewName"); custForUpdate.setEmail("email"); custForUpdate.setId("1"); // Update item without setting the registrationDate attribute. customerDynamoDbTable.updateItem(b -> b .item(custForUpdate) .ignoreNulls(Boolean.TRUE)); Customer updatedWithNullsIgnored = customerDynamoDbTable.getItem(customer); // registrationDate value is unchanged. logger.info(updatedWithNullsIgnored.toString()); customerDynamoDbTable.updateItem(custForUpdate); Customer updatedWithNulls = customerDynamoDbTable.getItem(customer); // registrationDate value is null because ignoreNulls() was not used. logger.info(updatedWithNulls.toString()); } } // Logged lines. Customer [id=1, custName=NewName, email=email, registrationDate=2023-04-05T16:32:32.056Z] Customer [id=1, custName=NewName, email=email, registrationDate=null]
Métodos básicos del cliente mejorado de DynamoDB
Los métodos básicos del cliente mejorado se corresponden con las operaciones del servicio de DynamoDB que les dan nombre. Los siguientes ejemplos muestran la variación más simple de cada método. Puede personalizar cada método pasando un objeto de solicitud mejorado. Los objetos de solicitud mejorados ofrecen la mayoría de las características disponibles en el cliente estándar de DynamoDB. Estas acciones se documentan por completo en la Referencia de la API de AWS SDK for Java 2.x .
El ejemplo usa la Clase Customer mostrada anteriormente.
// 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));
Comparar el cliente mejorado con el cliente estándar de DynamoDB
Las dos API de cliente de DynamoDB, estándar
Si bien ambas API de cliente admiten operaciones a nivel de datos, el cliente estándar de DynamoDB también admite operaciones a nivel de recursos. Las operaciones a nivel de recursos gestionan la base de datos, como la creación de copias de seguridad, la creación de listas y la actualización de tablas. La API de cliente mejorada admite un número selecto de operaciones a nivel de recursos, como la creación, descripción y eliminación de tablas.
Para ilustrar los diferentes enfoques utilizados por las dos API de cliente, los siguientes ejemplos de código muestran la creación de la misma tabla ProductCatalog
con el cliente estándar y el cliente mejorado.
Comparación: crear una tabla mediante el cliente estándar de DynamoDB
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)) );
Comparación: crear una tabla mediante el cliente mejorado de DynamoDB
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)) ) );
El cliente mejorado utiliza la siguiente clase de datos anotados. El cliente mejorado de DynamoDB asigna los tipos de datos de Java a los tipos de datos de DynamoDB para obtener un código menos detallado que sea más fácil de seguir. ProductCatalog
es un ejemplo del uso de una clase inmutable con el cliente mejorado de DynamoDB. El uso de clases inmutables para las clases de datos mapeados se analiza más adelante en este tema.
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); } } }
Los dos ejemplos de código siguientes de una escritura por lotes ilustran la imprecisión y la falta de seguridad de tipos cuando se utiliza el cliente estándar frente al cliente mejorado.
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()); }