DynamoDB PutItem in Java (AWS SDK v2)
PutItem scrive un Item intero e sostituisce qualsiasi Item esistente con la stessa chiave primaria (le azioni basate sugli Item spiegano in cosa differisce da UpdateItem). In AWS SDK for Java 2.x ogni attributo entra in un PutItemRequest come AttributeValue tipizzato, e il builder ti lascerà costruirne uno che non può in alcun modo essere valido.
Codice
import java.util.HashMap;
import java.util.Map;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
public class PutItemExample {
public static void main(String[] args) {
try (DynamoDbClient ddb = DynamoDbClient.builder()
.region(Region.US_EAST_1)
.build()) {
Map<String, AttributeValue> item = new HashMap<>();
item.put("Artist", AttributeValue.builder().s("Arturo Sandoval").build());
item.put("SongTitle", AttributeValue.builder().s("Cubano Chant").build());
item.put("AlbumTitle", AttributeValue.builder().s("Danzon").build());
item.put("Year", AttributeValue.builder().n("1994").build());
item.put("Awards", AttributeValue.builder().n("0").build());
Map<String, String> names = new HashMap<>();
names.put("#cond0", "Artist");
names.put("#cond1", "SongTitle");
PutItemRequest request = PutItemRequest.builder()
.tableName("Music")
.item(item)
.conditionExpression("attribute_not_exists(#cond0) AND attribute_not_exists(#cond1)")
.expressionAttributeNames(names)
.build();
try {
ddb.putItem(request);
System.out.println("Song written");
} catch (ConditionalCheckFailedException e) {
System.out.println("A song with that key already exists — not overwritten");
}
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
}
}
}Spiegazione
AttributeValue.builder().build() compila. Ed è anche impossibile da inviare. Il builder non ha alcun campo obbligatorio, quindi un attributo in cui hai dimenticato il .s(...) passa perfettamente il controllo di tipo e fallisce sul servizio:
DynamoDbException | ValidationException | Supplied AttributeValue is empty, must contain exactly one of the supported datatypesQuesta è la forma specifica di Java di un errore che altri SDK rendono impossibile: i types.AttributeValueMember* di Go sono tipi separati, quindi non c'è nulla da lasciare non impostato. Vedi "Supplied AttributeValue is empty" per la soluzione più ampia.
Un null Java passato a .s(...) non diventa un NULL DynamoDB. Questa è la versione che morde davvero, perché sembra un valore:
AttributeValue.builder().s(customer.getNotes()).build() // getNotes() returned nullNessuna NullPointerException viene sollevata alla costruzione. Il builder semplicemente non registra nulla, e la richiesta fallisce con l'identico messaggio Supplied AttributeValue is empty, puntando a un attributo che non avresti mai sospettato. Se vuoi un null vero, è AttributeValue.builder().nul(true).build(); più spesso vuoi omettere la voce. Nota che è l'opposto dell'SDK Go, dove un puntatore nil viene marshalled a NULL e crea silenziosamente un attributo; entrambi sono stati eseguiti sullo stesso motore lo stesso giorno.
getMessage() non è il messaggio del servizio. L'SDK aggiunge il proprio contesto, quindi la stringa è:
The conditional request failed (Service: DynamoDb, Status Code: 400, Request ID: 77a08ef1-a3a9-4f97-b309-4cb0741edd1a) (SDK Attempt Count: 1)Fai match su e.awsErrorDetails().errorCode() e leggi e.awsErrorDetails().errorMessage() per il testo nudo. Qualsiasi cosa confronti getMessage() con una stringa letterale si rompe a un retry, che cambia il conteggio dei tentativi.
Intercetta ConditionalCheckFailedException prima di DynamoDbException, e leggi cosa porta con sé. Estende DynamoDbException, quindi ordinare i blocchi catch al contrario rende irraggiungibile l'handler specifico. Sull'oggetto intercettato: statusCode() ha restituito 400 e retryable() ha restituito false, che è la risposta onesta per un rifiuto di logica di business. Aggiungi .returnValuesOnConditionCheckFailure("ALL_OLD") alla richiesta ed e.item() torna popolato con l'Item che ha bloccato la scrittura (cinque attributi nell'esecuzione qui sopra, Year come AttributeValue(N=1994)), così non ti serve un getItem di controllo per scoprire chi ha vinto.
I numeri entrano come stringhe attraverso .n(...). Il tipo N di DynamoDB è testo decimale sul wire, ed è ciò che impedisce a 1994 di diventare un double. .n(String.valueOf(year)) è l'idioma; non esiste un overload .n(int) a cui appigliarsi.
Il client è Closeable, e a vita lunga. Il try-with-resources qui sopra è giusto per un programma one-shot e sbagliato per un servizio: DynamoDbClient possiede un pool di connessioni HTTP ed è thread-safe, quindi costruiscine uno per applicazione e lascialo vivere. Crearne uno per richiesta è il bug di prestazioni Java più comune su questa API.
Preferisci i bean alle mappe di AttributeValue? Il DynamoDB Enhanced Client (software.amazon.awssdk.enhanced.dynamodb) mappa una classe annotata direttamente su un Item, il che elimina del tutto la trappola del builder vuoto. Costa una scansione riflessiva TableSchema.fromBean all'avvio, che StaticTableSchema evita se la cosa ti interessa.
Fallo visivamente
Ogni fallimento qui sopra parte da valori tipizzati costruiti a mano. Il convertitore JSON DynamoDB gratuito prende del JSON normale e restituisce la forma tipizzata, così puoi vedere esattamente come dovrebbe apparire l'Item sul wire prima di scrivere un solo AttributeValue.builder().
Per scrivere e modificare Item sulle tue tabelle — un form per attributo, selettori di tipo, risultato ricopiabile in Java — scarica DynoTable.
Esempi correlati
- DynamoDB PutItem in Go — la stessa scrittura condizionale con AWS SDK for Go v2, dove un puntatore nil fallisce nel modo opposto.
- DynamoDB UpdateItem in Java — modifica attributi specifici invece di sostituire l'Item.
- Condition expression di DynamoDB —
attribute_not_exists, locking ottimistico e altro. - DynamoDB ConditionalCheckFailedException — cosa solleva la condizione create-only quando l'Item esiste già.
- DynamoDB ValidationException — il catch-all per un Item o un'espressione malformati.
Riferimenti
- PutItem — Amazon DynamoDB API Reference
- Use PutItem with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- DynamoDbClient — AWS SDK for Java 2.x API Reference
- AttributeValue — AWS SDK for Java 2.x API Reference
- PutItemRequest — AWS SDK for Java 2.x API Reference
- Condition expressions — Amazon DynamoDB Developer Guide
Riprodotto il 2026-07-28 con AWS SDK for Java 2.49.4 su OpenJDK 26.0.1, su DynamoDB Local (amazon/dynamodb-local) sulla porta 9000. Il testo dell'eccezione, il codice di stato e il contenuto dell'Item qui sopra sono output catturato, copiato alla lettera.