JPA Auditing : LocalDateTime 과 ZonedDateTime 비교

kimdoha·2023년 8월 7일

[Database-Log]

목록 보기
1/1
post-thumbnail

ZonedDateTime

LocalDateTime + TimeZone 합쳐진 방식입니다.
ZonedDateTime = LocalDate + LocalTime + ZoneOffset + ZoneRegion

ZonedDateTime 객체를 생성할 때는, nowof의 정적 메소드를 통해 생성합니다.

ZonedDateTime now = ZonedDateTime.now();

ZonedDateTime nowSeoul = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));

ZonedDateTime birthday = ZonedDateTime.of(2000, 1, 1, 0, 0, ZoneId.of("Asia/Seoul"));
Now in Seoul is 2023-08-07T00:15:12.862+09:00[Asia/Seoul]
Now in Seoul is 2023-08-07T00:15:12.862+09:00[Asia/Seoul]
birthday is 2000-01-01T20:30+09:00[Asia/Seoul]

ZoneId vs. ZoneOffset

ZoneId는 타임존, ZoneOffSet은 시차를 나타냅니다.
ZoneOffSet은 UTC 기준으로 시간 차이를 양수나 음수로 나타내고,
ZoneId는 해당 시간 차이를 타임존 코드로 나타냅니다.

예를 들어 서울의 경우, 타임존 코드는 Asia/Seoul 시차는 +09:00 입니다.

ZoneOffset seoulZoneOffset = ZoneOffset.of("+09:00");
System.out.println("+09:00 Time = " + ZonedDateTime.now(seoulZoneOffset));

ZoneId seoulZoneId = ZoneId.of("Asia/Seoul");
System.out.println("Seoul Time = " + ZonedDateTime.now(seoulZoneId));
+09:00 Time = 2023-08-07T11:16:47.261+09:00
Seoul Time = 2023-08-07T11:16:47.261+09:00[Asia/Seoul]

ZonedDateTime과 String간 변환

문자열을 ZonedDateTime 변환하기 위해서는 ZonedDateTime.parse() 메소드를 사용합니다.

ZonedDateTime zdt1 = ZonedDateTime.parse("2002-06-18T20:30:00+09:00[Asia/Seoul]");

ZonedDateTime zdt2 = ZonedDateTime.parse("2002/06/18/ 20:30:00 KST", DateTimeFormatter.ofPattern("yyyy/MM/dd/ HH:mm:ss z"));

JPA Auditing 적용

Spring Data JPA 에서는 Auditing 기능을 제공합니다.
엔터티 생성되고 변경되는 시점을 Audit(감지)하여,
엔터티의 생성 시각, 수정 시각을 기록합니다.

LocalDateTime

@EnableJPAAuditing
@EnableJPAAuditing 어노테이션을 사용하여,
Auditing 을 활성화 해야합니다.

@EnableJPAAuditing
@SpringBootApplication
public class SampleApplication {
   public static void main(String[] args) {
       SpringApplication.run(SampleApplication.class, args);
   }
}

Post Entity

@Getter
@NoArgsConstructor
@Entity
@EntityListeners(AuditingEntityListener.class)
public class Post {

	@Id
    @GeneratedValue
    private Long id;
    
    private String title;
    
    private String content;
	
    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdAt;
    
    @LastModifiedDate
    private LocalDateTime updatedAt;
    
}

@EntityListeners
Auditing을 적용할 엔터티 클래스에 @EntityListeners 어노테이션을 적용합니다. 그러면 엔터티의 변화를 감지하여 매핑된 테이블의 데이터를 조작합니다.

이벤트 리스너로는AuditingEntityListener 클래스를 넣어줍니다.
해당 클래스는 Spring Data JPA에서 제공하는 이벤트 리스너로 엔터티의 영속, 수정 이벤트를 감지하는 역할을 합니다.

@CreateDate
생성일을 기록하기 위해 LocalDateTime 타입의 필드에 @CreatedDate 를 적용합니다.
또한 생성 일자의 수정을 막기 위해 @Column(updatable=false) 를 적용합니다.
이 후에는 엔터티가 생성됨을 감지하고 그 시점을 createdAt 필드에 기록합니다.

ZonedDateTime

Spring Data JPA 에서 사용하는
@CreatedDate, @LastModifiedDate
ZonedDateTime 을 지원하지 않습니다.

ZonedDateTime 타입의 형태로 AuditingEntityListener 를 이용하여
시간을 기록하려고 할 때 에러가 발생합니다.

Supported types are [org.joda.time.DateTime, org.joda.time.LocalDateTime, java.util.Date, java.lang.Long, long].; nested exception is java.lang.IllegalArgumentException:

@PrePersist / @PreUpdate
ZonedDateTime의 경우에는
JPA Entity의 라이프 사이클(생명 주기)을 관리하는 어노테이션을 이용합니다.

  • @PrePersist : persist() 메소드를 호출해서 엔티티를 영속성 컨텍스트에 관리하기 직전에 호출된다.

  • @PreUpdate : flush나 commit을 호출해서 엔티티를 데이터베이스에 수정하기 직전에 호출된다.

@Entity
public class Post {
	@Column(name = "created_at")
	private ZonedDateTime createdAt;
    
    @Column(name = "updated_at")
    private ZonedDateTime updatedAt;
    
    @PrePersist
    public void onPrePersist() {
       this.createdAt = ZonedDateTime.now();
       this.updatedAt = ZonedDateTime.now();
    }
    
    @PreUpdate
    public void onPreUpdate() {
       this.updatedAt = ZonedDateTime.now();
    }
}

0개의 댓글