- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2018-09-09T09:09:29+00:00","","")
[[AWSメモ]] >
* AWS Java SDKでDynamoDBのCRUDを書いてみる [#q4c74446]
#setlinebreak(on);
#contents
-- 関連
--- [[AWS Kinesis Client Libraryでコンシューマ開発]]
-- 参考
--- [[AWS SDK for Java 開発者ガイド>https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/welcome.html]] > [[AWS SDK for Java コード例>https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/prog-services.html]] > [[AWS SDK for Java を使用した DynamoDB の例>https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/examples-dynamodb.html]] > [[DynamoDB での項目の操作>https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/examples-dynamodb-items.html]]
--- [[AWS SDK for Java APIリファレンス>https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html]]
* AWS Java SDK の DynamoDB関連パッケージ [#h8aa9d32]
** AWS Java SDK の DynamoDB関連パッケージ [#h8aa9d32]
#html(<div style="padding-left:10px;">)
以下の com.amazonaws.services.dynamodbv2 が DynamoDB関連パッケージ。
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html
#html(</div>)
** Java SDK利用時の注意点 [#aa82bce4]
#html(<div style="padding-left:10px;">)
例えば、同じデータ登録を行う場合でも、様々なインターフェースが用意されている為、要件に応じて使い分ける必要がある。
例として、レコードを登録するインターフェースを挙げるが、ざっと見渡しただけで、これだけのインターフェースがある。
com.amazonaws.services.dynamodbv2.AmazonDynamoDB
|戻り値|メソッド|h
|PutItemResult|putItem(PutItemRequest request)|
|PutItemResult|putItem(String tableName, Map<String,AttributeValue> item)|
|PutItemResult|putItem(String tableName, Map<String,AttributeValue> item, String returnValues)|
com.amazonaws.services.dynamodbv2.document.Table
|戻り値|メソッド|h
|PutItemOutcome|putItem(Item item)|
|PutItemOutcome|putItem(Item item, Expected... expected)|
|PutItemOutcome|putItem(Item item, String conditionExpression, Map<String,String> nameMap, Map<String,Object> valueMap)|
|PutItemOutcome|putItem(PutItemSpec spec)|
※さらにバッチWrite 等は com.amazonaws.services.dynamodbv2.document.DynamoDB で提供されている。
#html(<div style="padding:5px;background:#eeffee;display:inline-block;border-radius:5px;border:1px solid #333;box-shadow:1px 1px 10px #ccc">)
個人的には、
AmazonDynamoDB.putItem(PutItemRequest request)、AmazonDynamoDB.updateItem(UpdateItemRequest request) 等の XxxxItemRequest 系を引数にとるメソッドか、
Table.putItem(PutItemSpec spec)、Table.updateItem(UpdateItemSpec spec) 等の XxxxItemSpec 系を引数にとるメソッドを使用しておけば大抵のケースには対応できる気はしている。
逆に、putItem(Item item) などを使用していると、登録結果のデータを戻り値で取得したいケースや、消費したキャパシティユニットを戻り値で得たいケースには対応できない。
※XxxxItemRequest とか XxxxItemSpec だと withReturnValues や withReturnConsumedCapacity で登録/更新結果や、キャパシティユニットも返却できるようになるので。
#html(</div>)
#html(</div>)
** DynamoDBMapperについて [#da7679f4]
#html(<div style="padding-left:10px;">)
Java版のSDKでは、DynamoDBMapper といういわゆるO/Rマッピングツールが提供されている。
''&color(red){ただし、なぜかデフォルトでMap型がサポートされていない。};''
※恐らく DynamoDBTypeConverted アノテーションを利用して、自力でコンバーターを作ればマッピング可能と思われる。
|タイトル|参考URL|h
|Java: DynamoDBMapper|https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBMapper.html|
|サポートされているデータの種類|https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBMapper.DataTypes.html|
|任意データのマッピング|https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBMapper.ArbitraryDataMapping.html|
#html(</div>)
** テスト用プロジェクトの作成 [#md68e52a]
#html(<div style="padding-left:10px;">)
https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/setup-project-maven.html
#myterm2(){{
mkdir aws-sdk-java-test && cd aws-sdk-java-test
gradle init --type java-application
rm -rf src/main/java/*
rm -rf src/test/java/*
}}
build.gradle の編集
#mycode2(){{
plugins {
id 'java'
id 'application'
}
mainClassName = 'ScanTable'
dependencies {
compile 'com.google.guava:guava:23.0'
//compile 'com.amazonaws:aws-java-sdk:latest.release'
compile 'com.amazonaws:aws-java-sdk-dynamodb:latest.release'
compile 'com.google.code.gson:gson:2.8.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
testCompile 'junit:junit:4.12'
}
repositories {
jcenter()
}
run {
// 引数で指定されたクラスを実行する
if (project.hasProperty('main')) {
main(project.main)
}
}
}}
#html(</div>)
** テーブルの作成 [#we0981db]
#html(<div style="padding-left:10px;">)
*** DDL格納用フォルダ作成 [#ra9f949b]
#html(<div style="padding-left:10px;">)
#myterm2(){{
mkdir -p src/test/resources/ddl
}}
#html(</div>)
*** テーブル定義の作成 [#pb4ab3e3]
#html(<div style="padding-left:10px;">)
src/test/resources/ddl/SampleTable.json
#mycode2(){{
{
"TableName": "SampleTable",
"AttributeDefinitions": [
{ "AttributeName": "pkey", "AttributeType": "S" },
{ "AttributeName": "skey", "AttributeType": "S" }
],
"KeySchema": [
{ "AttributeName": "pkey", "KeyType": "HASH" },
{ "AttributeName": "skey", "KeyType": "RANGE" }
],
"ProvisionedThroughput": { "WriteCapacityUnits": 1, "ReadCapacityUnits": 1 }
}
}}
#html(</div>)
*** テーブル作成 [#jf603ce0]
#html(<div style="padding-left:10px;">)
#myterm2(){{
aws dynamodb create-table --cli-input-json file://src/test/resources/ddl/SampleTable.json
}}
#html(</div>)
#html(</div>)
** テストデータの登録 [#d6c65409]
#html(<div style="padding-left:10px;">)
#myterm2(){{
aws dynamodb put-item --table-name SampleTable \
--item '{"pkey": {"S": "test0"}, "skey": {"S": "2018-01-01T00:00:00.001"}, "stringData": {"S": "testdata-001"} }'
aws dynamodb put-item --table-name SampleTable \
--item '{"pkey": {"S": "test0"}, "skey": {"S": "2018-01-01T00:00:00.002"}, "stringData": {"S": "testdata-002"} }'
aws dynamodb put-item --table-name SampleTable \
--item '{"pkey": {"S": "test0"}, "skey": {"S": "2018-01-01T00:00:00.003"}, "stringData": {"S": "testdata-003"} }'
aws dynamodb put-item --table-name SampleTable \
--item '{"pkey": {"S": "test0"}, "skey": {"S": "2018-01-01T00:00:00.004"}, "stringData": {"S": "testdata-004"} }'
aws dynamodb put-item --table-name SampleTable \
--item '{"pkey": {"S": "test0"}, "skey": {"S": "2018-01-01T00:00:00.005"}, "stringData": {"S": "testdata-005"} }'
}}
#html(</div>)
&br;
** 処理(CRUD)の作成 [#a3649cf0]
#html(<div style="padding-left:10px;">)
*** 検索処理(scan) [#r4f3d8c9]
#html(<div style="padding-left:10px;">)
src/main/java/ScanTable.java
#mycode2(){{
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;
import java.util.List;
import java.util.Map;
public class ScanTable {
private static AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
public static void main(String[] args){
ScanRequest request = new ScanRequest("SampleTable");
ScanResult result = amazonDynamoDB.scan(request);
Integer count = result.getCount();
System.out.println("#########################################");
System.out.println("count: " + count );
List<Map<String,AttributeValue>> items = result.getItems();
for (Map<String,AttributeValue> item : items) {
System.out.println(item);
}
System.out.println("#########################################");
}
}
}}
テスト実行
#myterm2(){{
gradle run -Pmain=ScanTable
}}
&br;
#html(</div>)
*** 登録処理 [#a3fbbdb1]
#html(<div style="padding-left:10px;">)
src/main/java/PutItem.java
#mycode2(){{
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class PutItem {
private static AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
public static void main(String[] args){
String datetime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS"));
String pkey = "test1";
String skey = datetime;
String stringData = "testdata-" + UUID.randomUUID().toString();
Map<String,AttributeValue> item = new HashMap<String,AttributeValue>();
item.put("pkey" , new AttributeValue().withS(pkey));
item.put("skey" , new AttributeValue().withS(skey));
item.put("stringData" , new AttributeValue().withS(stringData));
PutItemResult result = amazonDynamoDB.putItem(new PutItemRequest("SampleTable", item));
System.out.println("#########################################");
System.out.println(result);
System.out.println("#########################################");
}
}
}}
テスト実行
#myterm2(){{
gradle run -Pmain=PutItem
}}
&br;
#html(</div>)
*** 検索処理(query) [#le0b378d]
#html(<div style="padding-left:10px;">)
src/main/java/QueryTable.java
#mycode2(){{
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.QueryResult;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class QueryTable {
private static AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
public static void main(String[] args){
QueryRequest request = new QueryRequest("SampleTable");
Map<String,Condition> keyConditions = new HashMap<String,Condition>();
keyConditions.put("pkey", new Condition().withComparisonOperator(ComparisonOperator.EQ).withAttributeValueList(new AttributeValue("test1")));
request.setKeyConditions(keyConditions);
// KeyConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues を使用する場合
/*
request.setKeyConditionExpression("#pkey = :pkey");
request.setExpressionAttributeNames(new HashMap<String,String>(){
{put("#pkey", "pkey");}
});
request.setExpressionAttributeValues(new HashMap<String,AttributeValue>(){
{put(":pkey", new AttributeValue("test1"));}
});
*/
QueryResult result = amazonDynamoDB.query(request);
Integer count = result.getCount();
System.out.println("#########################################");
System.out.println("count: " + count );
List<Map<String,AttributeValue>> items = result.getItems();
for (Map<String,AttributeValue> item : items) {
System.out.println(item);
}
System.out.println("#########################################");
}
}
}}
テスト実行
#myterm2(){{
gradle run -Pmain=QueryTable
}}
&br;
#html(</div>)
*** 更新処理(update) [#m3a4985c]
#html(<div style="padding-left:10px;">)
src/main/java/UpdateItem.java
#mycode2(){{
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
import com.amazonaws.services.dynamodbv2.model.UpdateItemResult;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class UpdateItem {
private static AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
public static void main(String[] args){
Map<String, String> attributeNames = new HashMap<String,String>(){{
put("#stringData", "stringData");
} };
Map<String, AttributeValue> attributeValues = new HashMap<String, AttributeValue>(){{
put(":stringData", new AttributeValue().withS("testdata-" + UUID.randomUUID().toString()));
} };
Map<String, AttributeValue> key = new HashMap<String, AttributeValue>();
key.put("pkey", new AttributeValue().withS("test0"));
key.put("skey", new AttributeValue().withS("2018-01-01T00:00:00.001"));
UpdateItemRequest request = new UpdateItemRequest()
.withTableName("SampleTable")
.withKey(key)
//.withConditionExpression("#other = :other") // 条件付き更新を行う場合
.withUpdateExpression("set #stringData = :stringData")
.withExpressionAttributeNames(attributeNames)
.withExpressionAttributeValues(attributeValues);
UpdateItemResult result = amazonDynamoDB.updateItem(request);
System.out.println("#########################################");
System.out.println(result);
System.out.println("#########################################");
}
}
}}
テスト実行
#myterm2(){{
gradle run -Pmain=UpdateItem
}}
&br;
#html(</div>)
*** 削除処理(delete) [#oda04e6e]
#html(<div style="padding-left:10px;">)
src/main/java/DeleteItem.java
#mycode2(){{
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteItemResult;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class DeleteItem {
private static AmazonDynamoDB amazonDynamoDB = AmazonDynamoDBClientBuilder.standard().build();
public static void main(String[] args){
Map<String, AttributeValue> key = new HashMap<String, AttributeValue>();
key.put("pkey", new AttributeValue().withS("test0"));
key.put("skey", new AttributeValue().withS("2018-01-01T00:00:00.001"));
DeleteItemRequest request = new DeleteItemRequest()
.withTableName("SampleTable")
.withKey(key);
DeleteItemResult result = amazonDynamoDB.deleteItem(request);
System.out.println("#########################################");
System.out.println(result);
System.out.println("#########################################");
}
}
}}
テスト実行
#myterm2(){{
gradle run -Pmain=DeleteItem
}}
&br;
#html(</div>)
#html(</div>)