はじめに
Spring Cloud AWS 3.0を利用してDynamoDBへのアクセス方法をまとめる
環境
- Java 17
- Spring Boot 3.1.3
- Spring Cloud AWS 3.0.2
- DynamoDB local
- Gradle 8.2.1
DynamoDB localの設定
- docker-compose.yamlに下記の定義を行いDynamoDB Localのコンテナを起動
- dynamodb-adminを追加しているので、
http://localhost:8001/
にアクセスすればGUIでDynaamoDBに接続できる
docker-compose.yml
version: '3.8'
services:
dynamodb-local:
image: amazon/dynamodb-local:latest
container_name: dynamodb-local
user: root
command: -jar DynamoDBLocal.jar -sharedDb -dbPath /data
volumes:
- ./data/dynamodb:/data
ports:
- "8000:8000"
dynamo-admin:
image: aaronshaf/dynamodb-admin:latest
container_name: dynamo-admin
environment:
DYNAMO_ENDPOINT: http://dynamodb-local:8000
ports:
- "8001:8001"
depends_on:
- dynamodb-local
build.gradle
-
dependencies
に下記の依存関係を追加
build.gradle
implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.2")
implementation 'io.awspring.cloud:spring-cloud-aws-starter'
implementation 'io.awspring.cloud:spring-cloud-aws-starter-dynamodb'
application.yml
- DynamoDBの接続先を設定する(DynamoDB Localのポートを指定)
spring:
cloud:
aws:
dynamodb:
endpoint: http://localhost:4569
table-prefix:
パラメーターについては下記を参照
https://docs.awspring.io/spring-cloud-aws/docs/3.0.2/reference/html/index.html#configuration
spring-devtools.properties
-
spring-boot-devtools
を依存関係に追加していると下記の例外が発生したので抑止するためにsrc/main/resources/META-INF/spring-devtools.properties
を作成して下記を追加した
spring-devtools.properties
restart.include.dynamodb=/dynamodb-[-\\w\\d\.]+\.jar
restart.include.awspring=spring-cloud-aws-[-\\w\\d\.]+\.jar
例外
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:774)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:755)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:319)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at com.example.demo.HttpclientApplication.main(HttpclientApplication.java:35)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50)
Caused by: java.lang.ClassCastException: class com.example.demo.Person cannot be cast to class com.example.demo.Person (com.example.demo.Person is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @6ce9878a; com.example.demo.Person is in unnamed module of loader 'app')
at software.amazon.awssdk.enhanced.dynamodb.internal.mapper.ResolvedImmutableAttribute.lambda$create$0(ResolvedImmutableAttribute.java:54)
at software.amazon.awssdk.enhanced.dynamodb.mapper.StaticImmutableTableSchema.lambda$itemToMap$5(StaticImmutableTableSchema.java:507)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1092)
at software.amazon.awssdk.enhanced.dynamodb.mapper.StaticImmutableTableSchema.itemToMap(StaticImmutableTableSchema.java:505)
at software.amazon.awssdk.enhanced.dynamodb.mapper.WrappedTableSchema.itemToMap(WrappedTableSchema.java:67)
at software.amazon.awssdk.enhanced.dynamodb.mapper.WrappedTableSchema.itemToMap(WrappedTableSchema.java:67)
at software.amazon.awssdk.enhanced.dynamodb.internal.operations.PutItemOperation.generateRequest(PutItemOperation.java:90)
at software.amazon.awssdk.enhanced.dynamodb.internal.operations.PutItemOperation.generateRequest(PutItemOperation.java:45)
at software.amazon.awssdk.enhanced.dynamodb.internal.operations.CommonOperation.execute(CommonOperation.java:113)
at software.amazon.awssdk.enhanced.dynamodb.internal.operations.TableOperation.executeOnPrimaryIndex(TableOperation.java:59)
at software.amazon.awssdk.enhanced.dynamodb.internal.client.DefaultDynamoDbTable.putItem(DefaultDynamoDbTable.java:201)
at software.amazon.awssdk.enhanced.dynamodb.internal.client.DefaultDynamoDbTable.putItem(DefaultDynamoDbTable.java:209)
at software.amazon.awssdk.enhanced.dynamodb.internal.client.DefaultDynamoDbTable.putItem(DefaultDynamoDbTable.java:214)
at io.awspring.cloud.dynamodb.DynamoDbTemplate.save(DynamoDbTemplate.java:59)
at com.example.demo.HttpclientApplication.run(HttpclientApplication.java:51)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:771)
... 10 common frames omitted
使い方
テーブル定義
-
@DynamoDbBean
をクラスに付与 - getterに
@DynamoDbAttribute
を付与 - パーティションキーのgetterには
@DynamoDbPartitionKey
を付与
import java.util.UUID;
import lombok.Data;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
@DynamoDbBean
@Data
public class Person {
private UUID id;
private String name;
private String lastName;
@DynamoDbPartitionKey
@DynamoDbAttribute("id")
public UUID getId() {
return id;
}
@DynamoDbAttribute("name")
public String getName() {
return this.name;
}
@DynamoDbAttribute("lastName")
public String getLastName() {
return this.lastName;
}
}
テーブル作成
-
DynamoDbEnhancedClient
を利用する
@Autowired
private DynamoDbEnhancedClient dynamoDbEnhancedClient;
実装例
DynamoDbTable<Person> table = dynamoDbEnhancedClient.table("person", TableSchema.fromBean(Person.class));
table.createTable();
テーブルへの新規アイテム追加
-
DynamoDbTemplate
を利用する
@Autowired
private DynamoDbTemplate dynamoDbTemplate;
実装例
Person person = new Person();
person.setId(UUID.randomUUID());
person.setName("name");
person.setLastName("last");
Person save = dynamoDbTemplate.save(person);
log.info("save =[{}]", save); // save =[Person(id=5dac8d41-b5c9-4ef1-abbe-bacccde71ab0, name=name, lastName=last)]
テーブルのアイテム更新
-
DynamoDbTemplate
を利用する
@Autowired
private DynamoDbTemplate dynamoDbTemplate;
実装例
person.setName("update name");
Person update = dynamoDbTemplate.update(person);
log.info("update =[{}]", update); // update =[Person(id=5dac8d41-b5c9-4ef1-abbe-bacccde71ab0, name=update name, lastName=last)]
テーブルのアイテム検索
-
DynamoDbTemplate
を利用する
@Autowired
private DynamoDbTemplate dynamoDbTemplate;
実装例
Person load = dynamoDbTemplate.load(Key.builder().partitionValue(update.getId().toString()).build(), Person.class);
log.info("load =[{}]", load); // load =[Person(id=5dac8d41-b5c9-4ef1-abbe-bacccde71ab0, name=update name, lastName=last)]
テーブルのアイテム削除
-
DynamoDbTemplate
を利用する
@Autowired
private DynamoDbTemplate dynamoDbTemplate;
実装例
dynamoDbTemplate.delete(update);
最後に
- spring-devtoolsとAWSの相性が悪いのか
ClassCastException
が発生してその部分の解決に苦労したが、それ以外は簡単にDynamoDBに接続ができた - 検索系のQueryやScan関係のメソッドについてはまだ調べ切れていないのであとでまとめたい・・・
参考