createdAt / updatedAt 관리 방식 정리 (JPA vs DB)

JiMin LEE·2026년 2월 18일

1) 핵심 개념

  • createdAt: 레코드(엔티티)가 처음 생성된 시각
  • updatedAt: 레코드(엔티티)가 마지막으로 수정된 시각
  • 관리 방식은 크게 2가지:
    1) DB가 자동으로 채움/갱신
    2) 애플리케이션(JPA/Hibernate)이 채움/갱신

2) 방식 A: DB에서 관리 (DEFAULT / ON UPDATE 등)

예시 코드

@Column(
  columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP",
  insertable = false,
  updatable = false
)
private LocalDateTime createdAt;

@Column(
  columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP",
  insertable = false,
  updatable = false
)
private LocalDateTime updatedAt;

동작 방식

  • INSERT/UPDATE 시점에 DB가 createdAt/updatedAt을 자동으로 세팅/갱신
  • insertable=false, updatable=false로 인해 JPA는 해당 컬럼을 INSERT/UPDATE SQL에 포함하지 않음
    → 애플리케이션에서 값을 넣거나 변경할 수 없음

장점

  • 시간 기준이 DB 서버로 통일(멀티 앱 인스턴스에서도 일관성)
  • 애플리케이션 실수로 시간값을 변경하기 어려움(강제력)

단점 / 주의사항

  • DB 종속성이 큼
  • ON UPDATE CURRENT_TIMESTAMP는 주로 MySQL 계열에 친화적
  • PostgreSQL은 보통 트리거로 처리
  • H2 등은 모드에 따라 동작이 달라질 수 있음
  • 저장 직후 엔티티 객체의 createdAt/updatedAt이 즉시 채워지지 않을 수 있음
  • DB가 채운 값을 엔티티에서 바로 쓰려면 flush() 후 refresh() 또는 재조회가 필요할 수 있음
  • DB 자동 갱신은 “UPDATE가 실제로 발생”해야 반영됨(변경이 없으면 update가 안 나갈 수 있음)

3) 방식 B: 애플리케이션(JPA)에서 관리 (@PrePersist / @PreUpdate)

예시 코드

@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;

@Column(name = "updated_at", nullable = false)
private LocalDateTime updatedAt;

@PrePersist
protected void onCreate() {
  LocalDateTime now = LocalDateTime.now();
  this.createdAt = now;
  this.updatedAt = now;
}

@PreUpdate
protected void onUpdate() {
  this.updatedAt = LocalDateTime.now();
}

동작 방식

  • 엔티티가 처음 저장되기 직전: @PrePersist 실행 → createdAt, updatedAt 세팅
  • 엔티티가 수정되기 직전: @PreUpdate 실행 → updatedAt 갱신
  • JPA Dirty Checking으로 “변경이 감지되어 UPDATE가 발생”할 때 @PreUpdate가 호출됨

장점

  • DB 종류에 독립적(이식성 좋음): MySQL/PG/H2 등 대부분 동일하게 동작
  • 저장 직후에도 엔티티에 값이 들어있어 응답/테스트가 편함
  • nullable=false 등 제약을 코드로 명확히 표현 가능

단점 / 주의사항

  • 시간 기준이 애플리케이션 서버 시간
  • 멀티 서버 환경에서는 NTP 등으로 시간 동기화가 필요(보통 운영에서 해결)
  • save()를 호출했다고 항상 @PreUpdate가 실행되는 것은 아님
  • 실제로 값 변경이 없으면 UPDATE가 발생하지 않아 콜백도 실행되지 않을 수 있음

NTP란?

  • NTPNetwork Time Protocol의 약자이며,
    서버/컴퓨터들이 현재 시간을 정확하게 동기화하도록 해주는 표준 프로토콜이다.
    -> 여러 서버의 “시계”를 같은 시간으로 맞춰주는 동기화 시스템

왜 필요할까?

  • 서버가 여러 대인 환경에서는 각 서버의 시스템 시간이 조금씩 어긋날 수 있다.
  • 이런 상태에서 LocalDateTime.now()createdAt/updatedAt을 찍으면:
    • 서버 A와 서버 B의 시간이 달라 시간 순서가 뒤바뀌거나
    • 로그/정렬/감사 기록이 일관되지 않게 될 수 있다.

NTP가 해주는 일

  • NTP 서버(시간 기준 서버)와 주기적으로 통신해
    각 서버의 시간을 동일한 기준(보통 UTC)으로 맞춘다.

실무에서는 보통 어떻게 쓰나?

  • OS 수준에서 자동으로 동기화가 설정되어 있는 경우가 많다.
    • Linux: chrony 또는 ntpd
    • 클라우드(AWS/GCP/Azure)도 기본적인 시간 동기화 체계를 제공하는 편

0개의 댓글