Spring boot에서 AWS DynamoDB를 사용하여 CRUD를 하는 법에 대하여 간단히 정리해 보았다.
기타 No-sql DB와 다르게 기능 구현을 쉽게 할 수 있었던것 같다. 본 글의 spring 튜토리얼를 참고하여 작성 되었다.
준비
Local에서 dynamoDB을 docker로 구동하는 방법을 공유 한다.(이렇게 구동시 Key값은 공백으로 연결한다.)
version: '3.7'
services:
dynamodb:
image: amazon/dynamodb-local
container_name: my-dynamodb
hostname: dynamodb
restart: always
volumes:
- ./my-dynamodb-data:/home/dynamodblocal/data
ports:
- 8000:8000
command: "-jar DynamoDBLocal.jar -sharedDb -dbPath /home/dynamodblocal/data/"
구동 명령어는 아래와 같다.
docker-compose -f dynamodb.yml up -d
Maven 설정
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Lovelace-SR16</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.11.64</version>
</dependency>
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
Spring data와 asw dynamoDB에 대한 종속을 추가하면 기본적인 dependency는 해결 된다.
설정
DynamoDB를 사용하기 위해서는 전역에서의 설정이 필요한다. 본 글에서는 dynamoDBMaper를 사용하여 테이블 생성을 처리 했다.
@Configuration
@EnableDynamoDBRepositories
(basePackages = "com.baeldung.spring.data.dynamodb.repositories")
public class DynamoDBConfig {
@Value("${amazon.dynamodb.endpoint}")
private String amazonDynamoDBEndpoint;
@Value("${amazon.aws.accesskey}")
private String amazonAWSAccessKey;
@Value("${amazon.aws.secretkey}")
private String amazonAWSSecretKey;
@Bean
public AmazonDynamoDB amazonDynamoDB() {
AmazonDynamoDB amazonDynamoDB
= new AmazonDynamoDBClient(amazonAWSCredentials());
if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
}
return amazonDynamoDB;
}
@Bean
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB){
return new DynamoDBMapper(amazonDynamoDB, DynamoDBMapperConfig.DEFAULT);
}
@Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(
amazonAWSAccessKey, amazonAWSSecretKey);
}
}
DynamoDB 접근 정보는 환경 변수로 설정하고 그 값을 읽어 오는 방식으로 작업 했다.
Entity 생성
@DynamoDBTable(tableName = "ProductInfo")
public class ProductInfo {
private String id;
private String name;
private String cost;
private LocalDateTime createAt;
@DynamoDBHashKey
@DynamoDBAutoGeneratedKey
public String getId() {
return id;
}
public void setCost(String cost) {
this.cost = cost;
}
public void setName(String name) {
this.name = name;
}
@DynamoDBAttribute
public String getName() {
return name;
}
@DynamoDBAttribute
public String getCost() {
return cost;
}
@DynamoDBAttribute
public LocalDateTime getCreateAt(){
return createAt;
}
@Builder
public ProductInfo(String name, String cost, LocalDateTime createAt){
this.name = name;
this.cost = cost;
this.createAt = createAt;
}
}
@DynamoDBTable(tableName = "Comment"): Entity 클래스로 정의
@DynamoDBHashKey(attributeName = "id"): HashKey 필드로 유일한 값을 가지는 필드로 설정
@DynamoDBAttribute: 테이블 칼럼으로 설정
CRUD Repository 생성
@EnableScan
public interface ProductInfoRepository extends
CrudRepository<ProductInfo, String> {
Optional<ProductInfo> findById(String id);
}
CrudRepository에서 상속받으면 자동으로 CRUD을 구현 해준다.
CRUD에 대한 Test 작성
@Test
void TestCRUD(){
//create
ProductInfo productInfo = productInfoRepository.save(ProductInfo.builder()
.name("1")
.cost("20")
.createAt(LocalDateTime.now()).build());
//select
List<ProductInfo> foundProductInfos = (List<ProductInfo>) productInfoRepository.findAll();
//update
Optional<ProductInfo> optionalProductInfo = productInfoRepository.findById(productInfo.getId());
if(!optionalProductInfo.isPresent()){
//throw exception
}
ProductInfo resProductInfo = optionalProductInfo.get();
resProductInfo.setCost("30");
productInfoRepository.save(resProductInfo);
//delete
productInfoRepository.deleteById(productInfo.getId());
assertThat(productInfo.getId().isEmpty());
dynamoDBMapper.save(productInfo);
assertThat(!productInfo.getId().isEmpty());
}
Test class에서 @Befor && @after
@Test 호출 되기전과 된 후 호출되도록하는 Annotation이다. 본 예제에서는 이 Annotation을 이용하여 Test전 Table 생성과 삭제를 구현했다.
@BeforeEach
void createTable(){
CreateTableRequest createTableRequest = dynamoDBMapper.generateCreateTableRequest(ProductInfo.class)
.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
createTableRequest.getGlobalSecondaryIndexes().forEach(
idx ->idx
.withProvisionedThroughput(new ProvisionedThroughput(1L,1L))
.withProjection(new Projection().withProjectionType("ALL"))
);
TableUtils.createTableIfNotExists(amazonDynamoDB, createTableRequest);
}
@AfterEach
void deleteTable(){
DeleteTableRequest deleteTableRequest= dynamoDBMapper.generateDeleteTableRequest(ProductInfo.class);
TableUtils.deleteTableIfExists(amazonDynamoDB, deleteTableRequest);
}
Ref.
https://techblog.woowahan.com/2633/#spring-data-dynamodb로-쿼리-메서드-사용하기
https://reflectoring.io/spring-dynamodb/#accessing-dynamodb-with-spring-data
https://www.baeldung.com/spring-data-dynamodb
https://medium.com/platform-engineer/running-aws-dynamodb-local-with-docker-compose-6f75850aba1e
'DataBase' 카테고리의 다른 글
[DynamoDB] Partition Key 설계 (0) | 2021.12.21 |
---|---|
[Database] DynamoDB GSI 사용 (0) | 2021.12.19 |
PostgreSQL Transaction isolation level (0) | 2021.12.13 |
ORM 장단점 (0) | 2021.12.12 |
Postgres Failover 방법 (0) | 2021.12.12 |
Comment