JPA 생성 및 수정 날짜 자동 처리를 위한 공통 엔티티 만들기 @MappedSuperclass, @EnableJpaAuditing

서비스를 만들때 많은 엔티티가 생성일과 수정일을 가지고 있습니다. 이러한 필드를 각각의 엔티티마다 중복으로 작성하는 것은 번거로울 뿐 아니라 유지보수도 복잡해지고 가독성도 떨어집니다. 때문에 우리는 공통으로 갖고 있는 정보(생성일과 수정일)를 따로 엔티티로 만들어 상속받게 만들어보겠습니다.

 

@MappedSuperclass

JPA에서 상속 관계 매핑을 위해 사용되는 어노테이션입니다. 이 어노테이션을 사용하면 공통된 매핑 정보를 가진 부모 클래스를 정의할 수 있고, 여러 엔티티에서 공통 필드와 매핑 정보를 상속받아 사용할 수 있습니다.

`@MappedSuperclass` 어노테이션이 붙은 부모 클래스를 자식 엔티티가 상속받게 되면, 부모 클래스는 테이블로 생성되지 않고, 상속한 자식 클래스로 테이블이 생성됩니다. 

@Getter
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class DateEntity {

	@CreatedDate
	@Column(updatable = false)
	private LocalDateTime createDate;
    
	@LastModifiedDate
	private LocalDateTime modifyDate;
}

 

@CreatedDate, @LastModifiedDate

어노테이션 이름에서 알 수 있듯이 @CreatedDate는 데이터가 생성된 날짜를 넣고, @LastModifiedDate는 마지막 수정 날짜를 넣어줍니다. 엔티티의 생성일과 수정일을 자동으로 관리하기 위해서는 다음과 같은 작업을 해주어야 합니다.

 

1. @EnableJpaAuditing 어노테이션 추가

@EnableJpaAuditing 어노테이션은 엔티티의 생성일과 수정일을 자동으로 관리하기 위한 `Auditing`을 활성화시키는 역할을 합니다. 이를위해 메인 어플리케이션 클래스에 해당 어노테이션을 추가해주어야 합니다.   

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

  

2. @EntityListeners(AuditingEntityListener.class)

@EntityListeners 어노테이션은 엔티티의 변화를 감지하고 리스너 클래스를 통해 특정 이벤트에 대한 처리를 수행하는 역할을 합니다. 특정 엔티티 클래스에 적용하여 해당 엔티티의 변화를 감지하고 리스터 클래스를 호출합니다. 즉 위 예제에서는 AuditingEntityListener.class를 지정해주어서 엔티티의 생성 및 수정 시점에 자동으로 `@CreatedDate`와 `@LastModifiedDate 어노테이션이 붙은 필드를 업데이트하는 작업을 해줍니다. 

@Getter
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class DateEntity {
	//...
}

 

사용

이를 적용하고자 하는 엔티티 클래스에 상속만 해주면 적용됩니다.  

@Entity
public class Member extends DateEntity {
	//...
}

 

 

@Temporal 어노테이션을 사용하지 않는 이유?

@Temporal 어노테이션을 이용하여 TIMESTAMP 등을 사용하면 생성 및 수정 시간을 쉽게 적용할 수 있는데? 라고 생각하시는 분이 있을 수 있습니다. Java 8부터 `java.util.Date` 보다는 `java.time.LocalDate`나 `java.time.LocalDateTime`과같은 날짜 및 시간 클래스를 사용하는 것이 권장되고 있습니다. 하지만 @Temporal은 `java.util.Date`, `java.util.Calendar` 데이터 타입에만 적용할 수 있는 어노테이션이기 때문에 @Temporal은 최근 사용되지 않습니다. `java.time.LocalDate`와 `java.time.LocalDateTime`은 시간 단위까지 다룰 수 있기 때문에 @Temporal` 어노테이션이 없이도 더욱 정확하고 유연한 시간 관리를 할 수 있습니다.