DynamoDBMapper
类是 Amazon DynamoDB 的入口点。它提供对 DynamoDB 端点的访问,让您能够访问各个表中的数据。它还让您能够对项目执行各种创建、读取、更新和删除 (CRUD) 操作,并对表执行查询和扫描。此类提供了以下方法供您在 DynamoDB 中使用。
有关相应的 Javadoc 文档,请参阅AWS SDK for JavaAPI 参考的 DynamoDBMapper。
主题
save
将指定对象保存到表中。您要保存的对象是此方法唯一的必需参数。您可以使用 DynamoDBMapperConfig
对象提供可选配置参数。
如果具有相同主键的项目不存在,此方法就会在表中创建一个新项目。如果具有相同主键的项目存在,此方法就会更新现有项目。如果分区键和排序键的类型是 String、使用了 @DynamoDBAutoGeneratedKey
注释并且未初始化,那么系统会为其指定一个随机的全局唯一标识符 (UUID)。使用 @DynamoDBVersionAttribute
注释的版本字段会增加 1。此外,如果系统更新了版本字段或生成一个键,则该操作会使得系统更新传入的对象。
默认情况下,系统只会更新已映射的类属性对应的属性。项目中任何其他现有属性不会受到影响。但是,如果指定 SaveBehavior.CLOBBER
,您就可以强制相应的项目实现完全覆盖。
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER).build(); mapper.save(item, config);
如果您启用了版本控制,客户端和服务器端的项目版本就必须匹配。但是,如果使用的了 SaveBehavior.CLOBBER
选项,版本就无需相匹配。有关版本控制的更多信息,请参阅DynamoDB 和乐观锁(使用版本号)。
负载
检索表中的项目。您必须提供要检索的项目的主键。您可以使用 DynamoDBMapperConfig
对象提供可选配置参数。例如,您可以选择请求强一致性读取,以确保此方法只检索最新的项目值(如以下 Java 语句所示)。
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT).build(); CatalogItem item = mapper.load(CatalogItem.class, item.getId(), config);
默认情况下,DynamoDB 所返回的项目的值采用最终一致性。有关 DynamoDB 的最终一致性模式的信息,请参阅DynamoDB 读取一致性。
删除
删除表中的项目。您必须传入已映射类的对象实例。
如果您启用了版本控制,客户端和服务器端的项目版本就必须匹配。但是,如果使用的了 SaveBehavior.CLOBBER
选项,版本就无需相匹配。有关版本控制的更多信息,请参阅DynamoDB 和乐观锁(使用版本号)。
查询
查询表或二级索引。
假定您的 Reply
表存储了论坛话题回复,每个话题主题可以有 0 条或更多条回复。Reply
表的主键由 Id
和 ReplyDateTime
字段构成,其中 Id
是分区键,ReplyDateTime
是主键的排序键。
Reply ( Id, ReplyDateTime, ... )
假设您在 Reply
类和 DynamoDB 中对应的 Reply
表之间创建了一个映射。以下 Java 代码使用 DynamoDBMapper
查找特定话题主题在过去两周内的所有回复。
例
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);
该查询会一系列 Reply
对象。
在默认情况下,query
方法返回“延迟加载”集合。它最初只返回一页结果,然后在需要时发出服务调用请求下一页结果。要获取所有匹配项,请对 latestReplies
集合进行迭代。
请注意,对集合调用 size()
方法将会加载每个结果,以提供准确的计数。这可能会导致消耗大量预置的吞吐量,在数据量非常庞大的表上甚至可能会耗尽 JVM 中的所有内存。
要查询索引,您必须先将索引建模为映射器类。假设 Reply
表具有一个名为 PostedBy-Message-Index 的全局二级索引。此索引的分区键为 PostedBy
,排序键为 Message
。该索引中某个项目的类定义将如下所示。
@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
来查询此索引,以检索某位用户发布的消息的子集。如果您在表和索引之间没有冲突的映射并且已在映射器中建立映射,则无需指定索引名称。映射器将根据主键和排序键进行推断。以下代码示例查询全局二级索引。由于全局二级索引支持最终一致性读取,但不支持强一致性读取,因此您必须指定 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);
该查询会一系列 PostedByMessage
对象。
queryPage
查询表或二级索引并返回单页匹配结果。与 query
方法一样,您必须指定分区键值以及应用于排序键属性的查询筛选条件。但是,queryPage
仅返回第一“页”数据,即适合 1 MB 的数据量
扫描
扫描整个表或二级索引。您可以选择指定 FilterExpression
以筛选结果集。
假定您的 Reply
表存储了论坛话题回复,每个话题主题可以有 0 条或更多条回复。Reply
表的主键由 Id
和 ReplyDateTime
字段构成,其中 Id
是分区键,ReplyDateTime
是主键的排序键。
Reply ( Id, ReplyDateTime, ... )
如果您已经将 Java 类映射到 Reply
表,则可以使用 DynamoDBMapper
来扫描表。例如,以下 Java 代码扫描整个 Reply
表,仅返回了某一年内的回复。
例
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
集合进行迭代。
请注意,对集合调用 size()
方法将会加载每个结果,以提供准确的计数。这可能会导致消耗大量预置的吞吐量,在数据量非常庞大的表上甚至可能会耗尽 JVM 中的所有内存。
要扫描索引,您必须先将索引建模为映射器类。假设 Reply
表具有一个名为 PostedBy-Message-Index
的全局二级索引。此索引的分区键为 PostedBy
,排序键为 Message
。此索引的映射器类显示在 查询 部分。它使用 @DynamoDBIndexHashKey
和 @DynamoDBIndexRangeKey
注释来指定此索引的分区键和排序键。
下面的代码示例扫描 PostedBy-Message-Index
。该代码段并未使用扫描筛选条件,因此索引中的所有项目都会返回给您。
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
.withIndexName("PostedBy-Message-Index")
.withConsistentRead(false);
List<PostedByMessage> iList = mapper.scan(PostedByMessage.class, scanExpression);
Iterator<PostedByMessage> indexItems = iList.iterator();
scanPage
扫描表或二级索引并返回单页匹配结果。与 scan
方法一样,您可以选择指定 FilterExpression
来筛选结果集。但是,scanPage
仅返回第一“页”数据,即适合 1 MB 的数据量。
parallelScan
对整个表或二级索引执行并行扫描。您可以指定表的几个逻辑分段,并指定用于筛选结果的扫描表达式。parallelScan
将扫描任务分解为多个工作线程,每个逻辑分段各有一个工作线程;工作线程并行处理数据并返回结果。
以下 Java 代码示例对 Product
表执行并行扫描。
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
调用一次或多次 AmazonDynamoDB.batchWriteItem
方法,以在一个或多个表中保存对象。此方法不提供事务担保。
以下 Java 代码将两个项目(图书)保存到 ProductCatalog
表中。
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
使用主键检索一个或多个表中的多个项目。
以下 Java 代码检索两个不同表中的两个项目。
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
表中删除两个项目(图书)。
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
表中的一个项目。
// 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
调用一次 AmazonDynamoDB.transactWriteItems
方法以在一个或多个表中保存和删除对象。
有关事务特定的异常列表,请参阅 TransactWriteItems 错误。
有关 DynamoDB 事务和提供的原子性、一致性、隔离性和持久性 (ACID) 保证的更多信息,请参阅 Amazon DynamoDB Transactions。
注意
该方法不支持以下功能:
以下 Java 代码以事务方式将新项目分别写入到 Forum
和 Thread
表中。
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
调用一次 AmazonDynamoDB.transactGetItems
方法以从一个或多个表中加载对象。
有关事务特定的异常列表,请参阅 TransactGetItems 错误。
有关 DynamoDB 事务和提供的原子性、一致性、隔离性和持久性 (ACID) 保证的更多信息,请参阅 Amazon DynamoDB Transactions。
以下 Java 代码以事务方式分别从 Forum
和 Thread
表中加载一个项目。
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
评估指定的扫描表达式并返回匹配项目的数量。不返回任何项目数据。
generateCreateTableRequest
分析代表 DynamoDB 表的 POJO 类,并返回针对该表的 CreateTableRequest
。
createS3Link
创建 Amazon S3 中对象的链接。必须指定存储桶名称和用于唯一标识存储桶中的对象的键名称。
要使用 createS3Link
,您的映射器类必须定义 getter 和 setter 方法。以下代码示例通过将新属性和 getter/setter 方法添加到 CatalogItem
类对此加以说明。
@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。
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);
S3Link
类提供了许多用于操作 Amazon S3 中的对象的其他方法。有关更多信息,请参阅适用于 S3Link
的 Javadocs。
getS3ClientCache
返回用于访问 Amazon S3 的基础 S3ClientCache
。一个 S3ClientCache
就是一个用于 AmazonS3Client
对象的智能映射。如果您有多个客户端,则 S3ClientCache
可帮助您按 AWS 区域来组织客户端,并可以按需创建新的 Amazon S3 客户端。