DynamoDB Query in Java (AWS SDK v2)
queryPaginator im AWS SDK für Java 2.x sieht aus wie eine Collection und ist keine. Es ist ein Lazy-Re-Iterable, und der Unterschied zeigt sich auf deiner Rechnung, sobald du ein zweites Mal darüber iterierst. Wann Query überhaupt der richtige Read ist, steht in Query vs. Scan.
Code
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.QueryRequest;
import software.amazon.awssdk.services.dynamodb.model.QueryResponse;
public class QueryExample {
public static void main(String[] args) {
try (DynamoDbClient ddb = DynamoDbClient.builder()
.region(Region.US_EAST_1)
.build()) {
Map<String, String> names = new HashMap<>();
names.put("#hashKey", "Artist");
names.put("#rangeKey", "SongTitle");
Map<String, AttributeValue> values = new HashMap<>();
values.put(":hashKeyValue", AttributeValue.builder().s("Arturo Sandoval").build());
values.put(":rangeKeyValue", AttributeValue.builder().s("C").build());
QueryRequest request = QueryRequest.builder()
.tableName("Music")
.keyConditionExpression(
"#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)")
.expressionAttributeNames(names)
.expressionAttributeValues(values)
.build();
List<Map<String, AttributeValue>> items = new ArrayList<>();
for (QueryResponse page : ddb.queryPaginator(request)) {
items.addAll(page.items());
}
System.out.println("Found " + items.size() + " items");
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
}
}
}QueryIterable führt die Abfrage bei jeder Iteration erneut aus
Gegen ein Fixture aus 600 Songs, jeder ~3,9 KB und alle unter Artist = "Arturo Sandoval", kam ddb.queryPaginator(request) in 2,6 ms zurück und schickte nichts. Dann wurde dasselbe QueryIterable-Objekt zweimal durchlaufen:
queryPaginator(request) returned in 2.60 ms (class QueryIterable, 0 requests)
iteration 1: pages=3 items=600 capacity=284.5
iteration 2: pages=3 items=600 capacity=284.5 <- same objectZwei for-Schleifen über einer Variablen, 569 Leseeinheiten. Die Seiten wurden nie zwischengespeichert; jede Iteration läuft LastEvaluatedKey wieder von vorn ab. Wenn du die Items zweimal brauchst, leere das Iterable einmal in eine List, so wie es das Beispiel tut.
Die Kehrseite derselben Lazyness ist die Stelle, an der Fehler auftauchen. Bau eine Anfrage, deren Key Condition den Partition Key auslässt, und queryPaginator nimmt sie klaglos an, weil noch kein Aufruf stattgefunden hat:
queryPaginator(bad) constructed without throwing
threw on iteration: DynamoDbException / ValidationException /
Query condition missed key schema element / http 400Ein try-catch um den Builder herum fängt nichts. Es muss die Schleife umschließen — deshalb steckt im Beispiel der ganze Block in einem try.
Am 2026-07-28 gegen DynamoDB Local (amazon/dynamodb-local) mit software.amazon.awssdk:dynamodb 2.49.4 auf OpenJDK 26.0.1 gemessen.
Erklärung
ddb.queryPaginator(request).items()flacht die Seiten zu einemIterable<Map<String, AttributeValue>>ab und paginiert hinter deinem Rücken — die zweistufige Schleife im Beispiel schrumpft also auf eine, wenn du nur die Items willst. Es ist außerdem einSdkIterable,.stream()funktioniert also.- Zahlen sind
Stringim Builder.AttributeValue.builder().n("1994")ist kein Tippfehler für.n(1994)— dern()-Setter nimmt einenjava.lang.String, weil DynamoDB Zahlen als Dezimaltext transportiert, um binäre Float-Rundung zu vermeiden. Ein Java-intzu übergeben kompiliert nicht. keyConditionExpressionnimmt eine Gleichheit auf dem Partition Key plus höchstens eine Sort-Key-Bedingung (=,<,<=,>,>=,BETWEEN,begins_with);.scanIndexForward(false)dreht die Reihenfolge um und.indexName("...")richtet sie auf einen Sekundärindex.- Der Enhanced Client ist die andere Ergonomie.
software.amazon.awssdk.enhanced.dynamodbmappt annotierte Beans stattMap<String, AttributeValue>, und seinqueryliefert einPageIterable<T>mit derselben oben gemessenen Lazy-Re-Iteration-Semantik.
Mach es visuell
Sowohl #hashKey als auch #rangeKey sind in diesem Beispiel Aliase, zu denen dich nichts zwingt: Weder Artist noch SongTitle steht auf AWS' 573 Wörter langer Liste reservierter Wörter. Der Reserved-Words-Checker sagt dir, welche deiner Attributnamen die #-Behandlung wirklich brauchen — damit die Alias-Map kein Cargo-Kult mehr ist.
Um eine Key Condition gegen eine echte Tabelle auszuprobieren, bevor du den QueryRequest baust, lade DynoTable herunter und blättere durch die Ergebnisse in einem Grid.
Verwandte Beispiele
- DynamoDB Query in Go — dieselbe Abfrage mit AWS SDK für Go v2.
- DynamoDB Scan in Java — wenn du dich nicht per Key in eine Partition hängen kannst.
- Query vs. Scan — warum
Queryder richtige Standard ist. - Key Condition Expressions — jeder erlaubte Partition-/Sort-Key-Operator.
- „Query condition missed key schema element" — die Key Condition benennt das falsche Attribut oder überspringt den Partition Key.
- „Query key condition not supported" — ein Operator, den die Key Condition nicht nutzen kann, etwa contains oder eine zweite Sort-Key-Bedingung.