DynamoDBMapper Class
The DynamoDBMapper
class is the entry point to Amazon DynamoDB. It provides
access to a DynamoDB endpoint and enables you to access your data in various tables. It
also enables you to perform various create, read, update, and delete (CRUD) operations
on items, and run queries and scans against tables. This class provides the following
methods for working with DynamoDB.
For the corresponding Javadoc documentation, see DynamoDBMapper in the AWS SDK for Java API Reference.
Topics
save
Saves the specified object to the table. The object that you want to save is the
only required parameter for this method. You can provide optional configuration
parameters using the DynamoDBMapperConfig
object.
If an item that has the same primary key does not exist, this method creates a new
item in the table. If an item that has the same primary key exists, it updates the
existing item. If the partition key and sort key are of type String and are
annotated with @DynamoDBAutoGeneratedKey
, they are given a random
universally unique identifier (UUID) if left uninitialized. Version fields that are
annotated with @DynamoDBVersionAttribute
are incremented by one.
Additionally, if a version field is updated or a key generated, the object passed in
is updated as a result of the operation.
By default, only attributes corresponding to mapped class properties are updated.
Any additional existing attributes on an item are unaffected. However, if you
specify SaveBehavior.CLOBBER
, you can force the item to be completely
overwritten.
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER).build(); mapper.save(item, config);
If you have versioning enabled, the client-side and server-side item versions must
match. However, the version does not need to match if the
SaveBehavior.CLOBBER
option is used. For more information about
versioning, see DynamoDB and optimistic locking with
version number.
load
Retrieves an item from a table. You must provide the primary key of the item that
you want to retrieve. You can provide optional configuration parameters using the
DynamoDBMapperConfig
object. For example, you can optionally
request strongly consistent reads to ensure that this method retrieves only the
latest item values as shown in the following Java statement.
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT).build(); CatalogItem item = mapper.load(CatalogItem.class, item.getId(), config);
By default, DynamoDB returns the item that has values that are eventually consistent. For information about the eventual consistency model of DynamoDB, see DynamoDB read consistency.
delete
Deletes an item from the table. You must pass in an object instance of the mapped class.
If you have versioning enabled, the client-side and server-side item versions must
match. However, the version does not need to match if the
SaveBehavior.CLOBBER
option is used. For more information about
versioning, see DynamoDB and optimistic locking with
version number.
query
Queries a table or a secondary index.
Assume that you have a table, Reply
, that stores forum thread
replies. Each thread subject can have zero or more replies. The primary key of the
Reply
table consists of the Id
and
ReplyDateTime
fields, where Id
is the partition key
and ReplyDateTime
is the sort key of the primary key.
Reply ( Id, ReplyDateTime, ... )
Assume that you created a mapping between a Reply
class and the
corresponding Reply
table in DynamoDB. The following Java code uses
DynamoDBMapper
to find all replies in the past two weeks for a
specific thread subject.
Example
String forumName = "&DDB;"; String forumSubject = "&DDB; Thread 1"; String partitionKey = forumName + "#" + forumSubject; long twoWeeksAgoMilli = (new Date()).getTime() - (14L*24L*60L*60L*1000L); Date twoWeeksAgo = new Date(); twoWeeksAgo.setTime(twoWeeksAgoMilli); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); String twoWeeksAgoStr = df.format(twoWeeksAgo); Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":v1", new AttributeValue().withS(partitionKey)); eav.put(":v2",new AttributeValue().withS(twoWeeksAgoStr.toString())); DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>() .withKeyConditionExpression("Id = :v1 and ReplyDateTime > :v2") .withExpressionAttributeValues(eav); List<Reply> latestReplies = mapper.query(Reply.class, queryExpression);
The query returns a collection of Reply
objects.
By default, the query
method returns a "lazy-loaded" collection. It
initially returns only one page of results, and then makes a service call for the
next page if needed. To obtain all the matching items, iterate over the
latestReplies
collection.
Note that calling the size()
method on the collection will load every
result in order to provide an accurate count. This can result in a lot of
provisioned throughput being consumed, and on a very large table could even exhaust
all the memory in your JVM.
To query an index, you must first model the index as a mapper class. Suppose that
the Reply
table has a global secondary index named PostedBy-Message-Index. The partition key for this index is
PostedBy
, and the sort key is Message
. The class
definition for an item in the index would look like the following.
@DynamoDBTable(tableName="Reply") public class PostedByMessage { private String postedBy; private String message; @DynamoDBIndexHashKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "PostedBy") public String getPostedBy() { return postedBy; } public void setPostedBy(String postedBy) { this.postedBy = postedBy; } @DynamoDBIndexRangeKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "Message") public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } // Additional properties go here. }
The @DynamoDBTable
annotation indicates that this index is associated
with the Reply
table. The @DynamoDBIndexHashKey
annotation
denotes the partition key (PostedBy) of the index, and
@DynamoDBIndexRangeKey
denotes the sort key
(Message) of the index.
Now you can use DynamoDBMapper
to query the index, retrieving a
subset of messages that were posted by a particular user. You do not need to specify
the index name if you do not have conflicting mappings across tables and indexes and
the mappings are already made in the mapper. The mapper will infer based on the
primary key and sort key. The following code queries a global secondary index. Because global
secondary indexes support eventually consistent reads but not strongly consistent
reads, you must specify withConsistentRead(false)
.
HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":v1", new AttributeValue().withS("User A")); eav.put(":v2", new AttributeValue().withS("DynamoDB")); DynamoDBQueryExpression<PostedByMessage> queryExpression = new DynamoDBQueryExpression<PostedByMessage>() .withIndexName("PostedBy-Message-Index") .withConsistentRead(false) .withKeyConditionExpression("PostedBy = :v1 and begins_with(Message, :v2)") .withExpressionAttributeValues(eav); List<PostedByMessage> iList = mapper.query(PostedByMessage.class, queryExpression);
The query returns a collection of PostedByMessage
objects.
queryPage
Queries a table or secondary index and returns a single page of matching results. As with the
query
method, you must specify a partition key value and a query
filter that is applied on the sort key attribute. However, queryPage
returns only the first "page" of data, that is, the amount of data that fits in
1 MB
scan
Scans an entire table or a secondary index. You can optionally specify a
FilterExpression
to filter the result set.
Assume that you have a table, Reply
, that stores forum thread
replies. Each thread subject can have zero or more replies. The primary key of the
Reply
table consists of the Id
and
ReplyDateTime
fields, where Id
is the partition key
and ReplyDateTime
is the sort key of the primary key.
Reply ( Id, ReplyDateTime, ... )
If you mapped a Java class to the Reply
table, you can use the
DynamoDBMapper
to scan the table. For example, the following Java
code scans the entire Reply
table, returning only the replies for a
particular year.
Example
HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":v1", new AttributeValue().withS("2015")); DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withFilterExpression("begins_with(ReplyDateTime,:v1)") .withExpressionAttributeValues(eav); List<Reply> replies = mapper.scan(Reply.class, scanExpression);
By default, the scan
method returns a "lazy-loaded" collection. It
initially returns only one page of results, and then makes a service call for the
next page if needed. To obtain all the matching items, iterate over the
replies
collection.
Note that calling the size()
method on the collection will load every
result in order to provide an accurate count. This can result in a lot of
provisioned throughput being consumed, and on a very large table could even exhaust
all the memory in your JVM.
To scan an index, you must first model the index as a mapper class. Suppose that
the Reply
table has a global secondary index named PostedBy-Message-Index
.
The partition key for this index is PostedBy
, and the sort key is
Message
. A mapper class for this index is shown in the query section. It uses the
@DynamoDBIndexHashKey
and @DynamoDBIndexRangeKey
annotations to specify the index partition key and sort key.
The following code example scans PostedBy-Message-Index
. It does not
use a scan filter, so all of the items in the index are returned to you.
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withIndexName("PostedBy-Message-Index") .withConsistentRead(false); List<PostedByMessage> iList = mapper.scan(PostedByMessage.class, scanExpression); Iterator<PostedByMessage> indexItems = iList.iterator();
scanPage
Scans a table or secondary index and returns a single page of matching results. As with the
scan
method, you can optionally specify a
FilterExpression
to filter the result set. However,
scanPage
only returns the first "page" of data, that is, the amount
of data that fits within 1 MB.
parallelScan
Performs a parallel scan of an entire table or secondary index. You specify a number of
logical segments for the table, along with a scan expression to filter the results.
The parallelScan
divides the scan task among multiple workers, one for
each logical segment; the workers process the data in parallel and return the
results.
The following Java code example performs a parallel scan on the
Product
table.
int numberOfThreads = 4; Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":n", new AttributeValue().withN("100")); DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withFilterExpression("Price <= :n") .withExpressionAttributeValues(eav); List<Product> scanResult = mapper.parallelScan(Product.class, scanExpression, numberOfThreads);
batchSave
Saves objects to one or more tables using one or more calls to the
AmazonDynamoDB.batchWriteItem
method. This method does not provide
transaction guarantees.
The following Java code saves two items (books) to the ProductCatalog
table.
Book book1 = new Book(); book1.setId(901); book1.setProductCategory("Book"); book1.setTitle("Book 901 Title"); Book book2 = new Book(); book2.setId(902); book2.setProductCategory("Book"); book2.setTitle("Book 902 Title"); mapper.batchSave(Arrays.asList(book1, book2));
batchLoad
Retrieves multiple items from one or more tables using their primary keys.
The following Java code retrieves two items from two different tables.
ArrayList<Object> itemsToGet = new ArrayList<Object>(); ForumItem forumItem = new ForumItem(); forumItem.setForumName("Amazon DynamoDB"); itemsToGet.add(forumItem); ThreadItem threadItem = new ThreadItem(); threadItem.setForumName("Amazon DynamoDB"); threadItem.setSubject("Amazon DynamoDB thread 1 message text"); itemsToGet.add(threadItem); Map<String, List<Object>> items = mapper.batchLoad(itemsToGet);
batchDelete
Deletes objects from one or more tables using one or more calls to the
AmazonDynamoDB.batchWriteItem
method. This method does not provide
transaction guarantees.
The following Java code deletes two items (books) from the
ProductCatalog
table.
Book book1 = mapper.load(Book.class, 901); Book book2 = mapper.load(Book.class, 902); mapper.batchDelete(Arrays.asList(book1, book2));
batchWrite
Saves objects to and deletes objects from one or more tables using one or more
calls to the AmazonDynamoDB.batchWriteItem
method. This method does not
provide transaction guarantees or support versioning (conditional puts or
deletes).
The following Java code writes a new item to the Forum
table, writes
a new item to the Thread
table, and deletes an item from the
ProductCatalog
table.
// Create a Forum item to save Forum forumItem = new Forum(); forumItem.setName("Test BatchWrite Forum"); // Create a Thread item to save Thread threadItem = new Thread(); threadItem.setForumName("AmazonDynamoDB"); threadItem.setSubject("My sample question"); // Load a ProductCatalog item to delete Book book3 = mapper.load(Book.class, 903); List<Object> objectsToWrite = Arrays.asList(forumItem, threadItem); List<Book> objectsToDelete = Arrays.asList(book3); mapper.batchWrite(objectsToWrite, objectsToDelete);
transactionWrite
Saves objects to and deletes objects from one or more tables using one call to the
AmazonDynamoDB.transactWriteItems
method.
For a list of transaction-specific exceptions, see TransactWriteItems errors.
For more information about DynamoDB transactions and the provided atomicity, consistency, isolation, and durability (ACID) guarantees see Amazon DynamoDB Transactions.
Note
This method does not support the following:
The following Java code writes a new item to each of the Forum
and
Thread
tables, transactionally.
Thread s3ForumThread = new Thread(); s3ForumThread.setForumName("S3 Forum"); s3ForumThread.setSubject("Sample Subject 1"); s3ForumThread.setMessage("Sample Question 1"); Forum s3Forum = new Forum(); s3Forum.setName("S3 Forum"); s3Forum.setCategory("Amazon Web Services"); s3Forum.setThreads(1); TransactionWriteRequest transactionWriteRequest = new TransactionWriteRequest(); transactionWriteRequest.addPut(s3Forum); transactionWriteRequest.addPut(s3ForumThread); mapper.transactionWrite(transactionWriteRequest);
transactionLoad
Loads objects from one or more tables using one call to the
AmazonDynamoDB.transactGetItems
method.
For a list of transaction-specific exceptions, see TransactGetItems errors.
For more information about DynamoDB transactions and the provided atomicity, consistency, isolation, and durability (ACID) guarantees see Amazon DynamoDB Transactions.
The following Java code loads one item from each of the Forum
and
Thread
tables, transactionally.
Forum dynamodbForum = new Forum(); dynamodbForum.setName("DynamoDB Forum"); Thread dynamodbForumThread = new Thread(); dynamodbForumThread.setForumName("DynamoDB Forum"); TransactionLoadRequest transactionLoadRequest = new TransactionLoadRequest(); transactionLoadRequest.addLoad(dynamodbForum); transactionLoadRequest.addLoad(dynamodbForumThread); mapper.transactionLoad(transactionLoadRequest);
count
Evaluates the specified scan expression and returns the count of matching items. No item data is returned.
generateCreateTableRequest
Parses a POJO class that represents a DynamoDB table, and returns a
CreateTableRequest
for that table.
createS3Link
Creates a link to an object in Amazon S3. You must specify a bucket name and a key name, which uniquely identifies the object in the bucket.
To use createS3Link
, your mapper class must define getter and setter
methods. The following code example illustrates this by adding a new attribute and
getter/setter methods to the CatalogItem
class.
@DynamoDBTable(tableName="ProductCatalog") public class CatalogItem { ... public S3Link productImage; .... @DynamoDBAttribute(attributeName = "ProductImage") public S3Link getProductImage() { return productImage; } public void setProductImage(S3Link productImage) { this.productImage = productImage; } ... }
The following Java code defines a new item to be written to the
Product
table. The item includes a link to a product image; the
image data is uploaded to Amazon S3.
CatalogItem item = new CatalogItem(); item.setId(150); item.setTitle("Book 150 Title"); String amzn-s3-demo-bucket = "amzn-s3-demo-bucket"; String myS3Key = "productImages/book_150_cover.jpg"; item.setProductImage(mapper.createS3Link(amzn-s3-demo-bucket, myS3Key)); item.getProductImage().uploadFrom(new File("/file/path/book_150_cover.jpg")); mapper.save(item);
The S3Link
class provides many other methods for manipulating objects
in Amazon S3. For more information, see the Javadocs for S3Link
.
getS3ClientCache
Returns the underlying S3ClientCache
for accessing Amazon S3. An
S3ClientCache
is a smart Map for AmazonS3Client
objects. If you have multiple clients, an S3ClientCache
can help you
keep the clients organized by AWS Region, and can create new Amazon S3 clients on
demand.