벌써 우테캠의 2주 차 순서인 JPA도 얼마 남지 않았다.
시간이 정말 빠른거 같다! 특히 최근 2~3주 동안 너무너무 바빴어서 더 그런 거 같다.

암튼 오늘의 포스팅 주제는 @EnableJpaAuditing 어노테이션이다.
JPA 첫번째 과제를 하다가 배우고 느낀 것들을 정리해보고자 한다!
사건의 발단
created_at timestamp not null,
updated_at timestamp,
여러개의 엔티티를 DDL을 참고하여 JPA 매핑 작업을 하고 있었고,
대부분의 엔티티에는 위의 컬럼들이 공통적으로 구현되어 있었다.
나는 첫번째 회사에서도 사용해본 경험이 있었어서 바로 저 부분을 공통 클래스로 구현하여 상속을 받는 구조로 구현을 시도했다!
더불어 EnableJpaAuditing 기능을 사용하여 개발자가 직접 데이터를 설정하는 것이 아닌
엔티티의 INSERT, UPDATE 쿼리가 실행될 때 JPA가 자동으로 데이터를 설정해주는 방식으로 구현을 했다.
내가 원하는 기능으로 구현을 하려면 다음과 같이 구성을 해야 한다.
@EnableJpaAuditing
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseTime {
@CreatedDate
@Column(nullable = false)
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
public LocalDateTime getCreatedAt() {
return createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
}
이 부분 관련해서는 많은 포스팅이 있기 때문에 간략히 만 살펴보자.
- 먼저 애플리케이션 메인 메서드 상단에 @EnableJpaAuditing 어노테이션을 달아준다.
- 객체의 입장에서 공통 매핑 정보가 필요할 때 사용하는 @MappedSuperClass를 해당 엔티티에 달아준다.
- Entity에서 이벤트가 발생할 때마다 특정 로직을 실행하는 @EntityListeners를 달아준다.
- 실행할 특정 로직인 AuditingEntityListener.class를 추가한다.
내가 하고자 했던 거
위의 코드로 엔티티를 구성하면 BaseTime을 상속받은 엔티티들이 INSERT 되거나 UPDATE 될 때 자동으로 데이터를 설정해준다.
그런데 문득 이런 생각이 들었다.
INSERT에는 updatedAt을 NULL로 반영하고, UPDATE 일 때만 updatedAt을 반영하고 싶다!
그래서 어떤 블로그를 참고해서 작업을 진행해보았다. (https://wakestand.tistory.com/936)
- updateAt 컬럼에 insertable = false 라는 설정값을 추가하였다.
- 그러니 다음의 쿼리처럼 INSERT 할 때 값이 반영되지 않은걸 볼 수 있었다.
그런데,
이상하게도 실제 save() 함수가 실행된 후의 객체를 디버깅해보니
updatedAt에 데이터가 들어가져 있는 것이었다.
이것저것 해보고 디버깅을 계속해봐도 도저히 답이 나오지 않아서 우테캠 단체 슬랙에 문의를 드렸다.
댓글이 20개나 달렸다.
(근데 정말 본인들의 일처럼 열정적으로 도와주신다. 멋진 개발자 분들)
그래서 결론이 무엇이냐
거두절미하고 해결했던 해결방안이 무엇이었냐면
@EnableJpaAuditing(modifyOnCreate = false)
이었다!
위에서 작성했던 (insertable = false) 설정을 할 필요 없이 애플리케이션 메인 메서드 상단에 작성했던
@EnableJpaAuditing 어노테이션에 (modifyOnCreate=false) 값을 설정하는 거였다.
(이 자리를 빌려 큰 도움을 주신 백 XX님 그리고 또 다른 많은 분들 모두 모두 다시 한번 감사합니다!)
그렇다면 왜
저 설정을 주어야 하는 걸까?
이유를 알아보기 위해선 위에 BaseTime 엔티티에 설정해 주었던 AuditingEntityListener의 분석이 필요했다.
- AuditingEntityListener에는 touchForCreate와 touchForUpdate가 있다.
- 두 개의 구성은 거의 비슷한데 마지막 줄이 markCreated() / markModified()로 다르다.
하지만 두 가지 경우 모두 메서드를 타고 들어가 보면
- touch()라는 동일한 메서드가 실행된 결과를 리턴하게 된다!
- touch() 메소드 내부에는 touchAuditor() 메서드를 또 실행하는데 이 부분이 포인트이다!
마지막 두 개의 조건을 확인해보면 isNew (created 시에는 true가, modified 시에는 false가 들어간다.)라는 값과
modifyOnCreation이라는 값을 가지고 무언가의 행위를 하는데,
즉, modified 시에 modifyOnCreation 값에 따라 값을 세팅할지 말지를 결정하게 되는 것이다!
그리고 이 값은 자체적으로 기본값이 true로 되어있었다!
그래서 나는 @EnableJpaAuditing(modifyOnCreate=false)를 통해서 저 값을 변경하여 사용해야 했던 것이었다.
많은 분들의 도움을 받아서 문제를 해결하게 되었고,
테스트 코드를 통과할 때의 짜릿함이란 말로 표현할 수 없었다.
다시 한번 더 테스트와 코드 분석 그리고 주위에 능력 있고 열정 넘치는 개발자(?) 들의 중요성을 느끼게 되었다.
그럼 안녕! (너무 급하게 포스팅이 마무리된 감이 있네)
'Programing > Jpa' 카테고리의 다른 글
JPA Dynamic Query (1) - Querydsl 도입기 (0) | 2022.06.05 |
---|---|
JPA / Hibernate / Spring Data JPA (0) | 2022.05.30 |