package org.example.expert.domain.common.entity;
import jakarta.persistence.*;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAt;
@LastModifiedDate
@Column
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime modifiedAt;
@PrePersist
public void onPrePersist() { //생성시 나노초 저장안하기
this.createdAt = createdAt.truncatedTo(ChronoUnit.SECONDS);
this.modifiedAt = modifiedAt.truncatedTo(ChronoUnit.SECONDS);
}
@PreUpdate
public void onPreUpdate() { //업뎃시 나노초 저장안하기
this.modifiedAt = modifiedAt.truncatedTo(ChronoUnit.SECONDS);
}
}
이러한 추상클래스가 있어서 다른 entity 클래스들에서 상속받아 편하게 생성시간과 수정시간을 생성할 수 있다.
그러나 만약 어떤 클래스는 Timestamp 클래스를 상속 받더라도 수정시간은 필요없다면?
package org.example.expert.domain.log.entity;
import jakarta.persistence.*;
import lombok.NoArgsConstructor;
import org.example.expert.domain.common.entity.Timestamped;
import org.springframework.http.HttpStatus;
@Entity
@NoArgsConstructor
@AttributeOverrides({
@AttributeOverride(name = "modifiedAt", column = @Column(insertable = false, updatable = false))
})
public class Log extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String message;
@Enumerated(EnumType.STRING)
private HttpStatus httpStatus;
public Log(String message, HttpStatus httpStatus) {
this.message = message;
this.httpStatus = httpStatus;
}
}
로그를 저장하는 entity 클래스이다.
log는 저장만 필요할뿐 수정을 할 이유는 전혀 없어서 modifiedAt이 전혀 필요없다.
굳이 Timestamped를 상속을 받으면서 modifiedAt을 저장하고 싶지 않다면
@AttributeOverrides, @AttributeOverride를 사용하면 된다.
@AttributeOverrides와 @AttributeOverride는 JPA에서 사용하는 어노테이션으로, 엔티티 상속 관계에서 상속받은 속성의 매핑을 변경하거나 재정의할 때 사용한다.
@AttributeOverride
@AttributeOverride는 단일 속성을 재정의할 때 사용한다.
예를 들어, 상위 클래스의 필드 이름과 매핑 정보를 하위 클래스에서 다르게 지정하고 싶을 때 사용한다.
@AttributeOverride(name = "속성_이름", column = @Column(새로운_속성_정보))
위의 Log 클래스에서는
@AttributeOverride(name = "modifiedAt", column = @Column(insertable = false, updatable = false))
이런식으로 사용했는데 의미는 modifiedAt 필드의 속성을 생성과 업데이트가 불가능하게 Log 클래스에서 재정의한 것이다.
@AttributeOverrides
@AttributeOverrides는 여러 속성을 한꺼번에 재정의할 때 사용된다.
@AttributeOverride 어노테이션을 배열로 받아서 여러 속성을 재정의할 수 있다.
@AttributeOverrides({
@AttributeOverride(name = "속성_이름1", column = @Column(새로운_속성_정보1)),
@AttributeOverride(name = "속성_이름2", column = @Column(새로운_속성_정보2))
})
사실 위 Log 클래스에서는 사용할 필요가 없었다.
Log 클래스에 적용한 결과

H2 데이터베이스이다. MODIFIED_AT이 null인걸 확인 가능하다.
저렇게 필드는 생기고 null로 저장되는데 만약 필드조차 생기게 하고 싶지 않다면 Timestamped 클래스를 상속 받는게 아니라 따로 코드로 작성해주는게 좋아 보인다.
'spring' 카테고리의 다른 글
| entity를 저장할때 LocalDateTime에서 초를 저장하지 않는 법 (0) | 2025.03.13 |
|---|---|
| @WebMvcTest IllegalArgumentException: JPA metamodel must not be empty 오류 뜰때 (0) | 2025.03.06 |
| swagger 사용시 유용함. @Tag, @Operation (0) | 2025.03.06 |
| 테스트 코드 (0) | 2025.03.06 |
| 페이징처리할때 수동으로 처리하면서 공부한 내용 (0) | 2025.03.05 |