

# DynamoDBMapper クラス
<a name="DynamoDBMapper.Methods"></a>



`DynamoDBMapper` クラスは、Amazon DynamoDB のエントリポイントとなります。このクラスは、DynamoDB エンドポイントへのアクセスを提供し、さまざまなテーブルのデータを使用できるようにします。また、アイテムに対する作成、読み込み、更新、削除 (CRUD) の各オペレーションの実行、およびテーブルに対するクエリやスキャンを行うことができます。このクラスでは、DynamoDB を操作するために以下のメソッドが提供されます。

対応する Javadoc ドキュメントについては、*AWS SDK for Java API リファレンス*の「[DynamoDBMapper](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html)」を参照してください。

**Topics**
+ [save](#DynamoDBMapper.Methods.save)
+ [load](#DynamoDBMapper.Methods.load)
+ [削除](#DynamoDBMapper.Methods.delete)
+ [query](#DynamoDBMapper.Methods.query)
+ [queryPage](#DynamoDBMapper.Methods.queryPage)
+ [スキャン](#DynamoDBMapper.Methods.scan)
+ [scanPage](#DynamoDBMapper.Methods.scanPage)
+ [parallelScan](#DynamoDBMapper.Methods.parallelScan)
+ [batchSave](#DynamoDBMapper.Methods.batchSave)
+ [batchLoad](#DynamoDBMapper.Methods.batchLoad)
+ [batchDelete](#DynamoDBMapper.Methods.batchDelete)
+ [バッチ書き込み](#DynamoDBMapper.Methods.batchWrite)
+ [transactionWrite](#DynamoDBMapper.Methods.transactionWrite)
+ [transactionLoad](#DynamoDBMapper.Methods.transactionLoad)
+ [count](#DynamoDBMapper.Methods.count)
+ [generateCreateTableRequest](#DynamoDBMapper.Methods.generateCreateTableRequest)
+ [createS3Link](#DynamoDBMapper.Methods.createS3Link)
+ [getS3ClientCache](#DynamoDBMapper.Methods.getS3ClientCache)

## save
<a name="DynamoDBMapper.Methods.save"></a>

指定したオブジェクトがテーブルに保存されます。このメソッドで必要なパラメータは、保存するオブジェクトだけです。`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 およびバージョン番号を使用した楽観的ロック](DynamoDBMapper.OptimisticLocking.md)」を参照してください。

## load
<a name="DynamoDBMapper.Methods.load"></a>

テーブルから項目を取り出します。取得する項目のプライマリキーを入力する必要があります。`DynamoDBMapperConfig` オブジェクトを使用して、オプションの設定パラメータを入力できます。たとえば次の Java ステートメントに示すように、オプションで強力な整合性のある読み込みをリクエストして、このメソッドによって最新の項目の値だけを取り出すようにすることができます。

```
DynamoDBMapperConfig config = DynamoDBMapperConfig.builder()
    .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT).build();

CatalogItem item = mapper.load(CatalogItem.class, item.getId(), config);
```

DynamoDB のデフォルトでは、結果整合性のある値を持つ項目が返されます。DynamoDB の結果整合性モデルの詳細については、「[DynamoDB の読み取り整合性](HowItWorks.ReadConsistency.md)」を参照してください。

## 削除
<a name="DynamoDBMapper.Methods.delete"></a>

テーブルから項目を削除します。マッピングされたクラスのオブジェクトインスタンスを渡す必要があります。

バージョニングを有効にした場合は、クライアント側とサーバー側で項目のバージョンが一致する必要があります。ただし、`SaveBehavior.CLOBBER` オプションを使用する場合は、バージョンを一致させる必要はありません。バージョニングの詳細については、「[DynamoDB およびバージョン番号を使用した楽観的ロック](DynamoDBMapper.OptimisticLocking.md)」を参照してください。

## query
<a name="DynamoDBMapper.Methods.query"></a>

テーブルまたはセカンダリインデックスをクエリする

フォーラムスレッドの返信を格納する `Reply` というテーブルがあるとします。各スレッドの件名については、0 以上の返信を受け取ることができます。`Reply` テーブルのプライマリキーは、`Id` および `ReplyDateTime` フィールドで構成されます。ここで、`Id` はプライマリキーのパーティションキー、`ReplyDateTime` はソートキーを表します。

```
Reply ( Id, ReplyDateTime, ... )
```

`Reply` クラスと、それに対応する DynamoDB 内の `Reply` テーブルの間で、マッピングを作成したとします。次の Java コードでは、`DynamoDBMapper` を使用して特定のスレッド件名に対する過去 2 週間のすべての返信を検索しています。

**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);
```

このクエリでは、`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
<a name="DynamoDBMapper.Methods.queryPage"></a>

テーブルまたはセカンダリインデックスのクエリを実行し、一致した結果を 1 ページ返します。`query` メソッドと同様、パーティションキー値とソートキー属性に適用されるクエリフィルタを指定する必要があります。ただし `queryPage` では、データの最初の "ページ"、つまり 1 MB 以内に収まるデータ量のみが返されます。

## スキャン
<a name="DynamoDBMapper.Methods.scan"></a>

テーブル全体またはセカンダリインデックスをスキャンします。オプションで `FilterExpression` を指定して結果セットをフィルタリングできます。

フォーラムスレッドの返信を格納する `Reply` というテーブルがあるとします。各スレッドの件名については、0 以上の返信を受け取ることができます。`Reply` テーブルのプライマリキーは、`Id` および `ReplyDateTime` フィールドで構成されます。ここで、`Id` はプライマリキーのパーティションキー、`ReplyDateTime` はソートキーを表します。

```
Reply ( Id, ReplyDateTime, ... )
```

`Reply` テーブルに Java クラスをマッピングした場合は、`DynamoDBMapper` を使用してテーブルをスキャンできます。たとえば、以下の Java コードは、`Reply` テーブル全体をスキャンし、特定の年の返信のみを返します。

**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);
```

デフォルトでは、`scan` メソッドによって、「遅延ロード」されたコレクションが返されます。最初に結果が 1 ページのみ返され、必要に応じて、さらに次ページを要求するサービス呼び出しが行われます。一致するすべての項目を取得するには、`replies` コレクションを反復処理します。

コレクションで `size()` メソッドを呼び出すと、正確なカウントを提供するためにすべての結果がロードされます。これにより、プロビジョニングされたスループットが大量に消費され、非常に大きなテーブルでは JVM 内のすべてのメモリが消費されることさえあります。

インデックスをスキャンするには、最初にインデックスをマッパークラスとしてモデリングする必要があります。今、`Reply` テーブルには、`PostedBy-Message-Index` という名前のグローバルセカンダリインデックスがあると仮定します。このインデックスのパーティションキーは `PostedBy` キーで、ソートキーは `Message` です。このインデックスのマッパークラスは、[query](#DynamoDBMapper.Methods.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
<a name="DynamoDBMapper.Methods.scanPage"></a>

テーブルまたはセカンダリインデックスがスキャンされ、一致する結果が 1 ページ返されます。`scan` メソッドと同様に、オプションで `FilterExpression` を指定して結果セットをフィルタリングできます。ただし、`scanPage` では、データの最初の "ページ"、つまり、1 MB 以内に収まるデータ量のみが返されます。

## parallelScan
<a name="DynamoDBMapper.Methods.parallelScan"></a>

テーブル全体、またはセカンダリインデックスの並列スキャンが実行されます。テーブルの論理セグメントの数と、結果をフィルタするスキャン式を指定します。`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
<a name="DynamoDBMapper.Methods.batchSave"></a>

`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
<a name="DynamoDBMapper.Methods.batchLoad"></a>

テーブルのプライマリキーを使用して、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
<a name="DynamoDBMapper.Methods.batchDelete"></a>

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

## バッチ書き込み
<a name="DynamoDBMapper.Methods.batchWrite"></a>

`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
<a name="DynamoDBMapper.Methods.transactionWrite"></a>

`AmazonDynamoDB.transactWriteItems` メソッドに対する 1 回の呼び出しを使用して、1 つまたは複数のテーブルに対してオブジェクトの保存および削除を行います。

トランザクション固有の例外のリストについては、「[TransactWriteItems エラー](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html#API_TransactWriteItems_Errors)」を参照してください。

DynamoDB トランザクション、および提供されるアトミック性、整合性、分離、耐久性 (ACID) の保証の詳細については、「[DynamoDB トランザクションで複雑なワークフローを管理する](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)」を参照してください。

**注記**  
 このメソッドでは、以下をサポートしていません。  
[DynamoDBMapperConfig.SaveBehavior](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptionalConfig.html)

次の 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
<a name="DynamoDBMapper.Methods.transactionLoad"></a>

`AmazonDynamoDB.transactGetItems` メソッドへの 1 回の呼び出しを使用して、1 つまたは複数のテーブルからオブジェクトをロードします。

トランザクション固有の例外のリストについては、「[TransactGetItems エラー](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html#API_TransactGetItems_Errors)」を参照してください。

DynamoDB トランザクション、および提供されるアトミック性、整合性、分離、耐久性 (ACID) の保証の詳細については、「[DynamoDB トランザクションで複雑なワークフローを管理する](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html)」を参照してください。

次の 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
<a name="DynamoDBMapper.Methods.count"></a>

指定されたスキャン式の値を求め、一致する項目数を返します。項目データは返されません。

## generateCreateTableRequest
<a name="DynamoDBMapper.Methods.generateCreateTableRequest"></a>

DynamoDB テーブルに対応する POJO クラスを解析し、そのテーブルの `CreateTableRequest` を返します。

## createS3Link
<a name="DynamoDBMapper.Methods.createS3Link"></a>

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 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 のオブジェクトを操作するためのさまざまなメソッドが用意されています。詳細については、「[Javadocs for `S3Link`](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/S3Link.html)」を参照してください。

## getS3ClientCache
<a name="DynamoDBMapper.Methods.getS3ClientCache"></a>

Amazon S3 にアクセスする際の基盤となる `S3ClientCache` を返します。`S3ClientCache` は、`AmazonS3Client` オブジェクトのスマートマップです。複数のクライアントがある場合、`S3ClientCache` によって、AWS リージョン別にクライアントを整理しやすくなり、新しい Amazon S3 クライアントをオンデマンドで作成できるようになります。