Amazon DynamoDB
开发人员指南 (API Version 2012-08-10)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。点 击 Getting Started with Amazon AWS to see specific differences applicable to the China (Beijing) Region.

DynamoDBMapper

DynamoDBMapper 类是 DynamoDB 的入口点。它提供对 DynamoDB 终端节点的访问,可让您访问各种表中的数据、对项目执行各种 CRUD 操作,以及对表执行查询和扫描。此类提供了以下方法供您在 DynamoDB 中使用。

有关相应的 Javadoc 文档,请参阅 AWS SDK for Java API Reference 中的 DynamoDBMapper

save

将指定数据元保存到表中。您要保存的数据元是此方法唯一的必需参数。您可以使用 DynamoDBMapperConfig 数据元提供可选配置参数。

如果具有相同主键的项目不存在,此方法就会在表中创建一个新项目。如果具有相同主键的项目存在,此方法就会更新现有项目。如果类型是 String 且使用 @DynamoDBAutoGeneratedKey 注释的分区键和排序键未初始化,那么系统会指定一个随机的全局唯一标识符 (UUID)。使用 @DynamoDBVersionAttribute 注释的版本字段会增加 1。此外,如果系统更新了版本字段或生成一个键,则该操作会使得系统更新传入的数据元。

默认情况下,系统只会更新已映射的类属性对应的属性,而项目中任何其他现有属性不会受到影响。但是,如果指定 SaveBehavior.CLOBBER,您就可以强制相应的项目实现完全覆盖。

Copy
mapper.save(obj, new DynamoDBMapperConfig(DynamoDBMapperConfig.SaveBehavior.CLOBBER));

如果您启用了版本控制,客户端和服务器端的项目版本就必须匹配。但是,如果使用的了 SaveBehavior.CLOBBER 选项,版本就无需相匹配。有关版本控制的更多信息,请参阅乐观锁 (使用版本号)

load

检索表中的项目。您必须提供要检索的项目的主键。您可以使用 DynamoDBMapperConfig 数据元提供可选配置参数。例如,您可以选择请求强一致性读取,以确保此方法只检索最新的项目值 (如以下 Java 语句所示)。

Copy
CatalogItem item = mapper.load(CatalogItem.class, item.getId(), new DynamoDBMapperConfig(DynamoDBMapperConfig.ConsistentReads.CONSISTENT));

默认情况下,DynamoDB 所返回的项目的值采用最终一致性。有关 DynamoDB 的最终一致性模型的信息,请参阅读取一致性

delete

删除表中的项目。您必须传入已映射类的数据元实例。

如果您启用了版本控制,客户端和服务器端的项目版本就必须匹配。但是,如果使用的了 SaveBehavior.CLOBBER 选项,版本就无需相匹配。有关版本控制的更多信息,请参阅乐观锁 (使用版本号)

query

查询表或二级索引。只有当表或索引具有复合主键 (分区键和排序键) 时,您才能对其执行查询。此方法需要您提供分区键值和应用于排序键的查询筛选条件。筛选条件表达式包括一个条件和一个值。

假定您的 Reply 表存储了论坛话题回复,每个话题主题可以有 0 条或更多条回复。Reply 表的主键由 Id 和 ReplyDateTime 字段构成,其中 Id 是分区键,ReplyDateTime 是主键的排序键。

Copy
Reply ( Id, ReplyDateTime, ... )

现在,假设您在 DynamoDB 中的 Reply 类和对应的 Reply 表之间创建了一个映射。以下 Java 代码段使用 DynamoDBMapper 查找特定话题主题在过去两周内的所有回复。

Copy
String forumName = "DynamoDB"; String forumSubject = "DynamoDB 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);

该查询会一系列 Reply 数据元。

在默认情况下,query 方法返回“延迟加载”集合。它最初只返回一页结果,然后在需要时发出服务调用请求下一页结果。要获取的匹配所有项目,您只需对 latestReplies 集合进行迭代。

要查询索引,您必须先将索引建模为映射器类。假设 Reply 表有一个名为 PostedBy-Message-Index 的全局二级索引。此索引的分区键为 PostedBy,排序键为 Message。该索引中某个项目的类定义将如下所示:

Copy
@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. }

@DynamoDBTable 注释表示此索引与 Reply 表相关联。@DynamoDBIndexHashKey 注释表示此索引的分区键 (PostedBy),@DynamoDBIndexRangeKey 表示此索引的排序键 (Message)。

现在,您可以使用 DynamoDBMapper 来查询此索引,以检索某位用户发布的消息的子集。您必须指定 withIndexName,以便 DynamoDB 了解要查询哪个索引。在以下代码段中,我们查询的是全局二级索引。由于全局二级索引支持最终一致性读取,但不支持强一致性读取,因此我们必须指定 withConsistentRead(false)

Copy
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);

该查询会一系列 PostedByMessage 数据元。

queryPage

查询表或二级索引并返回单页匹配结果。与 query 方法一样,您必须指定分区键值以及应用于排序键属性的查询筛选条件。然而,queryPage 仅返回第一“页”数据,即适合 1 MB 的数据量。

scan

扫描整个表或二级索引。您可以选择指定 FilterExpression 以筛选结果集。

假定您的 Reply 表存储了论坛话题回复,每个话题主题可以有 0 条或更多条回复。Reply 表的主键由 Id 和 ReplyDateTime 字段构成,其中 Id 是分区键,ReplyDateTime 是主键的排序键。

Copy
Reply ( Id, ReplyDateTime, ... )

如果您已经将 Java 类映射到 Reply 表,则可以使用 DynamoDBMapper 来扫描表。例如,以下 Java 代码段扫描整个 Reply 表,仅返回了某一年内的回复。

Copy
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);

在默认情况下,scan 方法返回“延迟加载”集合。它最初只返回一页结果,然后在需要时发出服务调用请求下一页结果。要获取的匹配所有项目,您只需对 replies 集合进行迭代。

要扫描索引,您必须先将索引建模为映射器类。假设 Reply 表有一个名为 PostedBy-Message-Index 的全局二级索引。此索引的分区键为 PostedBy,排序键为 Message。此索引的映射器类显示在 query 部分,其中我们使用 @DynamoDBIndexHashKey@DynamoDBIndexRangeKey 注释来指定此索引的分区键和排序键。

以下代码段扫描 PostedBy-Message-Index。该代码段并未使用扫描筛选条件,因此索引中的所有项目都会返回给您。

Copy
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withIndexName("PostedBy-Message-Index") .withConsistentRead(false); List<PostedByMessage> indexItems = mapper.scan(PostedByMessage.class, scanExpression); Iterator<PostedByMessage> indexItems = iList.iterator();

scanPage

扫描表或二级索引并返回单页匹配结果。与 scan 方法一样,您可以选择指定 FilterExpression 来筛选结果集。然而,scanPage 仅返回第一“页”数据,即适合 1 MB 的数据量。

parallelScan

对整个表或二级索引执行并行扫描。您可以指定表的几个逻辑分段,并指定用于筛选结果的扫描表达式。parallelScan 将扫描任务分解为多个工作线程,每个逻辑分段各有一个工作线程;工作线程并行处理数据并返回结果。

以下 Java 代码段对 Product 表执行并行扫描。

Copy
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);

有关说明 parallelScan 用法的 Java 代码示例,请参阅示例:查询和扫描

batchSave

调用一次或多次 AmazonDynamoDB.batchWriteItem 方法,以在一个或多个表中保存数据元。此方法不提供事务担保。

以下 Java 代码段将两个项目 (图书) 保存到 ProductCatalog 表中。

Copy
Book book1 = new Book(); book1.id = 901; book1.productCategory = "Book"; book1.title = "Book 901 Title"; Book book2 = new Book(); book2.id = 902; book2.productCategory = "Book"; book2.title = "Book 902 Title"; mapper.batchSave(Arrays.asList(book1, book2));

batchLoad

使用主键检索一个或多个表中的多个项目。

以下 Java 代码段检索两个不同表中的两个项目。

Copy
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

调用一次或多次 AmazonDynamoDB.batchWriteItem 方法,以从一个或多个表中删除项目。此方法不提供事务担保。

以下 Java 代码段删除 ProductCatalog 表中的两个项目 (图书)。

Copy
Book book1 = mapper.load(Book.class, 901); Book book2 = mapper.load(Book.class, 902); mapper.batchDelete(Arrays.asList(book1, book2));

batchWrite

调用一次或多次 AmazonDynamoDB.batchWriteItem 方法,以在一个或多个表中和删除保存数据元。此方法不提供事务担保,也不支持版本控制 (有条件放置或删除)。

以下 Java 代码段向 Forum 表写入新项目、向 Thread 表写入新项目,然后删除 ProductCatalog 表中的项目。

Copy
// Create a Forum item to save Forum forumItem = new Forum(); forumItem.name = "Test BatchWrite Forum"; // Create a Thread item to save Thread threadItem = new Thread(); threadItem.forumName = "AmazonDynamoDB"; threadItem.subject = "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);

count

评估指定的扫描表达式并返回匹配项目的数量。不返回任何项目数据。

generateCreateTableRequest

分析代表 DynamoDB 表的 POJO 类,并返回针对该表的 CreateTableRequest

创建 Amazon S3 中对象的链接。必须指定存储桶名称和用于唯一标识存储桶中的对象的键名称。

要使用 createS3Link,您的映射器类必须定义 getter 和 setter 方法。以下代码段通过将新属性和 getter/setter 方法添加到 CatalogItem 类对此加以说明:

Copy
@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; } ... }

以下 Java 代码定义了一个要写入 Product 表的新项目。该项目包含某个产品图像的链接;图像数据会上传至 Amazon S3。

Copy
CatalogItem item = new CatalogItem(); item.id = 150; item.title = "Book 150 Title"; String myS3Bucket = "myS3bucket"; String myS3Key = "productImages/book_150_cover.jpg"; item.setProductImage(mapper.createS3Link(myS3Bucket, myS3Key)); item.getProductImage().uploadFrom(new File("/file/path/book_150_cover.jpg")); mapper.save(item);

S3Link 类提供了许多用于操作 Amazon S3 中的对象的其他方法。有关更多信息,请参阅适用于 S3Link 的 Javadocs

getS3ClientCache

返回用于访问 Amazon S3 的基础 S3ClientCache。一个 S3ClientCache 就是一个用于 AmazonS3Client 对象的智能映射。如果您有多个客户端,则 S3ClientCache 可帮助您按区域来组织客户端,并可以按需创建新的 Amazon S3 客户端。