DynamoDB는 AWS에서 제공하는 Key-Value 기반의 서버리스 NoSQL 데이터베이스이다.
- 데이터를 파티션 단위로 저장하고 관리한다.
- 파티션 키(해시 키)를 기준으로 해시 함수를 적용해 특정 파티션에 데이터를 분산 저장한다.
분산형 해시 테이블을 서버리스 환경에서 제공하는 데이터베이스라 할 수 있다.
Auto Scaling
, 고가용성
, 빠른 응답 속도
등의 이점을 가지고 있다.
AWS 콘솔에서 테이블을 생성한다.
테이블에 대한 정보를 입력한다.
테이블 이름은 test
, 파티션 키는 user_id
로 설정해주었다.
DynamoDB에 접근하기 위한 IAM 사용자를 생성하고, 아래와 같은 권한을 부여한다.
AmazonDynamoDBFullAccess
발급받은 access key
와 secret key
는 복사해두었다가 Spring Boot 설정 파일에 사용한다.
implementation platform('software.amazon.awssdk:bom:2.28.11')
implementation 'software.amazon.awssdk:dynamodb-enhanced'
implementation 'software.amazon.awssdk:dynamodb'
implementation 'software.amazon.awssdk:regions'
aws:
region: ap-northeast-2
dynamodb:
table-name: test
credentials:
access-key: {your-access-key}
secret-key: {your-secret-key}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
@Configuration
public class DynamoDBConfig {
@Value("${aws.region}")
private String region;
@Value("${aws.credentials.access-key}")
private String accessKey;
@Value("${aws.credentials.secret-key}")
private String secretKey;
@Bean
public DynamoDbClient dynamoDbClient() {
return DynamoDbClient.builder()
.region(Region.of(region))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(accessKey, secretKey)))
.build();
}
@Bean
public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
return DynamoDbEnhancedClient.builder()
.dynamoDbClient(dynamoDbClient)
.build();
}
}
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;
//@Getter @Setter 롬북 사용하지 않고 직접 getter, setter 작성
@DynamoDbBean
public class User {
private String userId;
private String name;
// 파티션 키 설정
// DynamoDbAttribute는 DynamoDB 속성명과 매핑
@DynamoDbPartitionKey
@DynamoDbAttribute("user_id")
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
@DynamoDbAttribute("name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
❗ DynamoDB Enhanced Client에서 Lombok이 인식되지 않는 이슈 ❗
DynamoDbEnhancedClient
는 런타임 리플렉션(reflection)을 사용하지 않고, 명시적으로 작성된 getter 메서드를 통해 매핑을 수행한다.
따라서 Lombok이 자동으로 생성하는 getUserId(), getName() 같은 메서드는 내부적으로 존재하더라도,@DynamoDbPartitionKey
,@DynamoDbAttribute
등의 어노테이션이 직접 작성된 메서드에만 적용되기 때문에 무시될 수 있다.
=> 따라서 Lombok을 사용한다면 일반 필드에서 사용하고, DynamoDB 매핑에 필요한 메서드는 명시적으로 작성해야한다!
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
// 유저 저장 API
@PostMapping
public String saveUser(@RequestBody User user) {
userService.saveUser(user);
return "User saved successfully!";
}
// 유저 조회 API
@GetMapping("/{userId}")
public User getUserById(@PathVariable String userId) {
return userService.getUserById(userId);
}
}
DynamoDB Enhanced Client를 이용하여 유저 데이터를 저장하고 조회한다.
import org.springframework.stereotype.Service;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
@Service
public class UserService {
private final DynamoDbEnhancedClient dynamoDbEnhancedClient;
private final DynamoDbTable<User> userTable;
public UserService(DynamoDbEnhancedClient dynamoDbEnhancedClient) {
this.dynamoDbEnhancedClient = dynamoDbEnhancedClient;
this.userTable = dynamoDbEnhancedClient.table("test", TableSchema.fromBean(User.class));
}
// 유저 저장
public void saveUser(User user) {
userTable.putItem(user);
}
// 파티션 키로 유저 조회
public User getUserById(String userId) {
return userTable.getItem(r -> r.key(k -> k.partitionValue(userId)));
}
}