generated from cotes2020/chirpy-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
525 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
title: LocalDateTime 저장 에러 | ||
date: 2023-08-10 18:20:00 +/-TTTT | ||
categories: [Spring, Spring Data DynamoDB] | ||
tags: [spring, dynamodb, troubleshooting] # TAG names should always be lowercase | ||
--- | ||
|
||
## 문제 상황 | ||
|
||
LocalDateTime을 DynamoDB에 저장하려고 했으나, 다음과 같은 에러가 발생하였습니다. | ||
|
||
``` | ||
InvalidDefinitionException: Joda date/time type `org.joda.time.LocalDateTime` not supported by default | ||
``` | ||
|
||
## 해결 과정 | ||
|
||
LocalDateTime parsing 에러로 추측하였으며, | ||
|
||
직접 LocalDateTime을 바꿔주는 Custom Converter를 작성하여 해당 에러를 해결해 줄 수 있었습니다. | ||
|
||
```java | ||
public static class LocalDateTimeConverter implements DynamoDBTypeConverter<Date, LocalDateTime> { | ||
@Override | ||
public Date convert(LocalDateTime source) { | ||
return Date.from(source.toInstant(ZoneOffset.UTC)); | ||
} | ||
|
||
@Override | ||
public LocalDateTime unconvert(Date source) { | ||
return source.toInstant().atZone(TimeZone.getDefault().toZoneId()).toLocalDateTime(); | ||
} | ||
} | ||
``` | ||
|
||
이후, 사용하고자 하는 Entity에 적용해주면 됩니다. | ||
|
||
- POCHAK의 경우, BaseEntity의 LocalDateTime attribute에 **@DynamoDBTypeConverted(converter = LocalDateTimeConverter.class)** 애노테이션을 추가해주었습니다. | ||
|
||
```java | ||
public class BaseEntity { | ||
|
||
... | ||
|
||
@LastModifiedDate | ||
@DynamoDBAttribute | ||
@DynamoDBTypeConverted(converter = LocalDateTimeConverter.class) | ||
private LocalDateTime lastModifiedDate; | ||
|
||
... | ||
} | ||
``` | ||
|
||
## 참고 자료 | ||
|
||
- [Spring Boot에서 Repository로 DynamoDB 조작하기 - 우아한 기술 블로그](https://techblog.woowahan.com/2633/) |
112 changes: 112 additions & 0 deletions
112
_posts/2023-08-10-spring-data-dynamodb-partitionkey-and-sortkey.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
--- | ||
title: Partition Key와 Sort Key를 같이 사용할 때 | ||
date: 2023-08-10 18:20:00 +/-TTTT | ||
categories: [Spring, Spring Data DynamoDB] | ||
tags: [spring, dynamodb, troubleshooting] # TAG names should always be lowercase | ||
--- | ||
|
||
## 문제 상황 | ||
|
||
POCHAK은 원테이블 설계로, `Partition Key`와 `Sort Key`를 모두 사용하여 설계하였습니다. | ||
|
||
하지만 Spring Data DynamoDB와 연결하는 과정에서 `BeanCreationException`이 발생하였습니다. | ||
|
||
이를 해결하기 위해 알아보는 과정에서 Partition Key와 Sort Key를 같이 사용하는 경우, **CrudRepository를 사용할 때 PK와 SK를 조합한 Id 클래스가 따로 있어야 한다는 점**을 알게되고 에러를 해결한 과정을 정리합니다! | ||
|
||
## 문제 해결 과정 | ||
|
||
### UserId Class | ||
|
||
- UserId 클래스를 다음과 같이 설정합니다. User에서 설정한 PK와 SK의 조합으로 이루어집니다. | ||
- 유의할 점은 UserId 클래스는 Serializable을 구현`implements`해야 합니다. | ||
|
||
```java | ||
public class UserId implements Serializable { | ||
private static final long serialVersionUID = 1L; | ||
|
||
private String handle; | ||
private String userSK = "USER#"; | ||
|
||
@DynamoDBHashKey | ||
public String getHandle() { | ||
return handle; | ||
} | ||
|
||
public void setHandle(String handle) { | ||
this.handle = handle; | ||
} | ||
|
||
@DynamoDBRangeKey | ||
public String getUserSK() { | ||
return userSK; | ||
} | ||
|
||
public void setUserSK(String userSK) { | ||
this.userSK = userSK; | ||
} | ||
} | ||
``` | ||
|
||
### User Class | ||
|
||
User의 PK, SK의 getter, setter를 ID에서 받아오고(getter), ID을 변경하도록(setter) 설정해줍니다. | ||
|
||
- 참고로 보통 모든 Entity의 attribute는 SDK에서 사용하기 위해서 getter와 setter를 필수로 가지고 있어야 합니다. 다만, userId는 getter와 setter가 있어서는 안됩니다. | ||
- 이 외에도 ID 클래스는 꼭 다음과 같이 **지연 생성**을 해주어야 합니다. | ||
|
||
```java | ||
@NoArgsConstructor | ||
@DynamoDBTable(tableName = "pochakdatabase") | ||
public class User extends BaseEntity { | ||
|
||
@Id // ID class should not have getter and setter. | ||
private UserId userId; | ||
|
||
private String handle; // PK | ||
|
||
private String userSK; // SK | ||
|
||
... | ||
|
||
@DynamoDBHashKey(attributeName = "PartitionKey") | ||
public String getHandle() { | ||
return userId != null ? userId.getHandle() : null; | ||
} | ||
|
||
public void setHandle(String handle) { | ||
if (userId == null) { | ||
userId = new UserId(); | ||
} | ||
userId.setHandle(handle); | ||
} | ||
|
||
@DynamoDBRangeKey(attributeName = "SortKey") | ||
public String getUserSK() { | ||
return userId != null ? userId.getUserSK(): null; | ||
} | ||
|
||
public void setUserSK(String userSK) { | ||
if (userId == null) { | ||
userId = new UserId(); | ||
} | ||
userId.setUserSK(userSK); | ||
} | ||
... | ||
} | ||
``` | ||
|
||
### UserCrudRepository interface | ||
|
||
이렇게 설정하면 CrudRepository를 구현하는 UserCrudRepository 클래스는 다음과 같이 작성할 수 있습니다. | ||
|
||
- 저장소는 꼭 ID 클래스 - 여기서는 UserId 클래스 - 를 사용해야 합니다. | ||
|
||
```java | ||
@EnableScan | ||
public interface UserCrudRepository extends DynamoDBCrudRepository<User, UserId> { | ||
} | ||
``` | ||
|
||
## 참고 자료 | ||
|
||
- [Use Hash Range Keys - derjust:spring-data-dynamodb](https://github.com/derjust/spring-data-dynamodb/wiki/Use-Hash-Range-keys) |
Oops, something went wrong.