DynamoDBMapper クラス
DynamoDBMapper
クラスは、Amazon DynamoDB のエントリポイントとなります。このクラスは、DynamoDB エンドポイントへのアクセスを提供し、さまざまなテーブルのデータを使用できるようにします。また、アイテムに対する作成、読み込み、更新、削除 (CRUD) の各オペレーションの実行、およびテーブルに対するクエリやスキャンを行うことができます。このクラスでは、DynamoDB を操作するために以下のメソッドが提供されます。
対応する Javadoc ドキュメントについては、AWS SDK for Java API リファレンスの「DynamoDBMapper」を参照してください。
トピック
save
指定したオブジェクトがテーブルに保存されます。このメソッドで必要なパラメータは、保存するオブジェクトだけです。DynamoDBMapperConfig
オブジェクトを使用して、オプションの設定パラメータを入力できます。
同じプライマリキーを持つ項目が存在しない場合は、このメソッドによってテーブル内に新しい項目が作成されます。同じプライマリキーを持つ項目が存在する場合は、その既存の項目が更新されます。パーティションキーとソートキーが String 型で、@DynamoDBAutoGeneratedKey
によって注釈が付けられている場合、初期化しなければ、ランダムな UUID (Universally Unique Identifier) が与えられます。@DynamoDBVersionAttribute
で注釈が付けられたバージョンフィールドは、バージョンが 1 ずつ増えていきます。さらに、バージョンフィールドが更新されるかキーが生成されると、オペレーションの結果として、渡されたオブジェクトが更新されます。
デフォルトでは、マップされたクラスプロパティに対応する属性のみが更新されます。アイテムのその他の既存の属性には影響はありません。ただし、SaveBehavior.CLOBBER
を指定すると、項目が完全に上書きされるようにすることができます。
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER).build(); mapper.save(item, config);
バージョニングを有効にした場合は、クライアント側とサーバー側で項目のバージョンが一致する必要があります。ただし、SaveBehavior.CLOBBER
オプションを使用する場合は、バージョンを一致させる必要はありません。バージョニングの詳細については、「DynamoDB およびバージョン番号を使用した楽観的ロック」を参照してください。
load
テーブルから項目を取り出します。取得する項目のプライマリキーを入力する必要があります。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 およびバージョン番号を使用した楽観的ロック」を参照してください。
query
テーブルまたはセカンダリインデックスをクエリする
フォーラムスレッドの返信を格納する Reply
というテーブルがあるとします。各スレッドの件名については、0 以上の返信を受け取ることができます。Reply
テーブルのプライマリキーは、Id
および ReplyDateTime
フィールドで構成されます。ここで、Id
はプライマリキーのパーティションキー、ReplyDateTime
はソートキーを表します。
Reply ( Id, ReplyDateTime, ... )
Reply
クラスと、それに対応する DynamoDB 内の Reply
テーブルの間で、マッピングを作成したとします。次の Java コードでは、DynamoDBMapper
を使用して特定のスレッド件名に対する過去 2 週間のすべての返信を検索しています。
例
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
メソッドによって、「遅延ロード」されたコレクションが返されます。最初に結果が 1 ページのみ返され、必要に応じて、さらに次ページを要求するサービス呼び出しが行われます。一致するすべての項目を取得するには、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
テーブルまたはセカンダリインデックスのクエリを実行し、一致した結果を 1 ページ返します。query
メソッドと同様、パーティションキー値とソートキー属性に適用されるクエリフィルタを指定する必要があります。ただし queryPage
では、データの最初の "ページ"、つまり 1 MB 以内に収まるデータ量のみが返されます。
scan
テーブル全体またはセカンダリインデックスをスキャンします。オプションで FilterExpression
を指定して結果セットをフィルタリングできます。
フォーラムスレッドの返信を格納する Reply
というテーブルがあるとします。各スレッドの件名については、0 以上の返信を受け取ることができます。Reply
テーブルのプライマリキーは、Id
および ReplyDateTime
フィールドで構成されます。ここで、Id
はプライマリキーのパーティションキー、ReplyDateTime
はソートキーを表します。
Reply ( Id, ReplyDateTime, ... )
Reply
テーブルに Java クラスをマッピングした場合は、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
メソッドによって、「遅延ロード」されたコレクションが返されます。最初に結果が 1 ページのみ返され、必要に応じて、さらに次ページを要求するサービス呼び出しが行われます。一致するすべての項目を取得するには、replies
コレクションを反復処理します。
コレクションで size()
メソッドを呼び出すと、正確なカウントを提供するためにすべての結果がロードされます。これにより、プロビジョニングされたスループットが大量に消費され、非常に大きなテーブルでは JVM 内のすべてのメモリが消費されることさえあります。
インデックスをスキャンするには、最初にインデックスをマッパークラスとしてモデリングする必要があります。今、Reply
テーブルには、PostedBy-Message-Index
という名前のグローバルセカンダリインデックスがあると仮定します。このインデックスのパーティションキーは PostedBy
キーで、ソートキーは Message
です。このインデックスのマッパークラスは、query セクションに示されています。また、@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
テーブルまたはセカンダリインデックスがスキャンされ、一致する結果が 1 ページ返されます。scan
メソッドと同様に、オプションで FilterExpression
を指定して結果セットをフィルタリングできます。ただし、scanPage
では、データの最初の "ページ"、つまり、1 MB 以内に収まるデータ量のみが返されます。
parallelScan
テーブル全体、またはセカンダリインデックスの並列スキャンが実行されます。テーブルの論理セグメントの数と、結果をフィルタするスキャン式を指定します。parallelScan
では、スキャンタスクが複数のワーカーに分割され、論理セグメントごとに 1 つのワーカーが割り当てられます。ワーカーは、データを並列に処理し、結果を返します。
次の 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
メソッドに対する 1 つ以上の呼び出しを使用して、1 つ以上のテーブルにオブジェクトを保存します。このメソッドでは、トランザクション保証はなされません。
次の Java コードでは、2 つの項目 (書籍) を 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
テーブルのプライマリキーを使用して、1 つ以上のテーブルから複数の項目を取り出します。
次の Java コードでは、2 つの異なるテーブルから 2 つの項目を取得します。
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
メソッドに対する 1 つ以上の呼び出しを使用して、1 つ以上のテーブルからオブジェクトを削除します。このメソッドでは、トランザクション保証はなされません。
次の Java コードでは、2 つの項目 (書籍) を ProductCatalog
テーブルから削除します。
Book book1 = mapper.load(Book.class, 901); Book book2 = mapper.load(Book.class, 902); mapper.batchDelete(Arrays.asList(book1, book2));
バッチ書き込み
AmazonDynamoDB.batchWriteItem
メソッドに対する 1 つ以上の呼び出しを使用して、1 つ以上のテーブルに対してオブジェクトの保存および削除を行います。このメソッドではトランザクション保証はなされず、バージョニング(条件付き入力または削除)もサポートされません。
次の 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
メソッドに対する 1 回の呼び出しを使用して、1 つまたは複数のテーブルに対してオブジェクトの保存および削除を行います。
トランザクション固有の例外のリストについては、「TransactWriteItems エラー」を参照してください。
DynamoDB トランザクション、および提供されるアトミック性、整合性、分離、耐久性 (ACID) の保証の詳細については、「DynamoDB トランザクションで複雑なワークフローを管理する」を参照してください。
注記
このメソッドでは、以下をサポートしていません。
次の 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
メソッドへの 1 回の呼び出しを使用して、1 つまたは複数のテーブルからオブジェクトをロードします。
トランザクション固有の例外のリストについては、「TransactGetItems エラー」を参照してください。
DynamoDB トランザクション、および提供されるアトミック性、整合性、分離、耐久性 (ACID) の保証の詳細については、「DynamoDB トランザクションで複雑なワークフローを管理する」を参照してください。
次の 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 メソッドを 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 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 のオブジェクトを操作するためのさまざまなメソッドが用意されています。詳細については、「Javadocs for S3Link
」を参照してください。
getS3ClientCache
Amazon S3 にアクセスする際の基盤となる S3ClientCache
を返します。S3ClientCache
は、AmazonS3Client
オブジェクトのスマートマップです。複数のクライアントがある場合、S3ClientCache
によって、AWS リージョン別にクライアントを整理しやすくなり、新しい Amazon S3 クライアントをオンデマンドで作成できるようになります。