[Spring Boot] JPA 사용시 생성/수정 시간 자동화 하기

윤동환·2023년 2월 20일
0
post-thumbnail

생성시간/수정시간 자동화

JPA Auditing?

JPA에서는 Audit이라는 기능을 제공하고 있습니다.
Audit은 감시하다, 감사하다라는 뜻으로 Spring Data JPA에서 시간에 대해서 자동으로 값을 넣어주는 기능입니다.
도메인을 영속성 컨텍스트에 저장하거나 조회를 수행한 후에 update를 하는 경우 매번 시간 데이터를 입력하여 주어야 하는데, audit을 이용하면 자동으로 시간을 매핑하여 데이터베이스의 테이블에 넣어주게 됩니다.

Java8에서 LocalDate와 LocalDateTime이 등장하며 기존 Date와 Calendar 클래스의 문제점을 해결했습니다.

Date와 Calendar 문제점
1. 불변객체가 아니다. -> 멀티스레드 환경에서 언제든 문제 발생 가능
2. Calendar.OCTOBER의 숫자값이 9이다. -> 개발자들의 혼란 야기
참고하면 좋은 Naver D2 글

주의사항
spring boot 1.x 버정의 경우 Hibernate 5.2.10 버전 이상으로 설정 필요

domain pacage에 BaseTimeEntity 클래스 생성

package orm.example.springboot.domain.posts;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

@Getter
@MappedSuperclass //JPA Entity 클래스들이 해당 추상 클래스를 상속할 경우 createDate, modifiedDate를 컬럼으로 인식
@EntityListeners(AuditingEntityListener.class) //BaseTimeEntity 클래스에 Auditing 기능을 포함시킴
public abstract class BaseTimeEntity { //추상화 이유
    @CreatedDate
    private LocalDateTime createDate; //Entity가 생성되어 저장될 때 시간이 자동 저장

    @LastModifiedDate
    private LocalDateTime modifiedDate; //조회한 Entity의 값을 변경할 때 시간이 자동 저장
}

어노테이션 설명
1. @MappedSuperclass
JPA Entity 클래스들이 BaseTimeEntity을 상속할 경우 필드들(createdDate,
modifiedDate)도 칼럼으로 인식하도록 합니다.
2. @EntityListeners(AuditingEntityListener.class)
BaseTimeEntity 클래스에 Auditing 기능을 포함시킵니다.
3. @CreatedDate
Entity가 생성되어 저장될 때 시간이 자동 저장됩니다.
4. @LastModifiedDate
조회한 Entity의 값을 변경할 때 시간이 자동 저장됩니다.

Posts Class에 BaseTimeEntity 적용

이제 @MapperdSuperclass를 활성화시키기위해 Posts 클래스로 BaseTimeEntity를 상속받도록 수정해야합니다.

Posts Class

@Getter // 6
@NoArgsConstructor // 5
@Entity // 1
public class Posts extends BaseTimeEntity {
	...
}

JPA Auditing 어노테이션 활성화

Application Class에 활성화 어노테이션 추가하기

Application Class

@EnableJpaAuditing
@SpringBootApplication
public class Application {
	...
}

Test 코드 작성

import ...

@RunWith(SpringRunner.class)
@SpringBootTest
public class PostsRepositoryTest {
    @Autowired
    PostsRepository postsRepository;

    @After // 1
    public void cleanup() {
        postsRepository.deleteAll();
    }

   	...

    @Test
    public void BaseTimeEntityTest_register() {
        //given
        LocalDateTime now = LocalDateTime.of(2023,2,20,0,0,0);
        postsRepository.save(Posts.builder()
                .title("title")
                .content("content")
                .author("author")
                .build());
        //when
        List<Posts> postsList = postsRepository.findAll();

        //then
        Posts posts = postsList.get(0);

        System.out.println(">>>>>>> cresteDate=" + posts.getCreatedDate()+", modifiedDate=" + posts.getModifiedDate());

        assertThat(posts.getCreatedDate()).isAfter(now);
        assertThat(posts.getModifiedDate()).isAfter(now);
    }
}

LocalDateTime now = LocalDateTime.of(2023,2,20,0,0,0);
now 변수로 받은 오늘 날 기준으로 isAfter()함수를 통해 생성 및 변경되는 시간이 now 이후인지 체크하며 문제 발생을 줄인다.

now가 저장이후 시간대를 나타낸다면 테스트 실행시

이러한 에러가 발생한다.

테스트 결과

생성날짜와 변경날짜 모두 같은 시간대임을 확인할 수 있다.

profile
모르면 공부하고 알게되면 공유하는 개발자

0개의 댓글