1. BaseEntity를 만드는 이유
프로젝트를 진행하다 보면 모든 테이블에 created_at, updated_at 같은 생성일/수정일 컬럼이 반복된다. 매번 직접 추가하면 코드 중복도 많고, 수정 시점 관리도 번거롭다.
이런 반복을 없애고 일관성 있는 엔티티 구조를 유지하기 위해 BaseEntity를 만든다.
1-1. BaseEntity 코드
package com.serverCommerce.smzShop.common.domain;
import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
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;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {
@CreatedDate
@Column(nullable = false, updatable = false, name = "created_at")
private LocalDateTime createdAt;
@LastModifiedDate
@Column(name = "updated_at")
private LocalDateTime updatedAt;
}
2. BaseEntity가 필요한 이유
2-1. 모든 엔티티에 공통적으로 필요한 필드 관리
거의 모든 테이블에 생성일, 수정일이 존재한다. 이걸 엔티티마다 중복 선언하면 유지보수가 어렵고 실수도 많아진다.
BaseEntity를 공통 부모 클래스로 만들어 상속시키면 모든 엔티티에 자동으로 이 필드가 포함된다.
@Entity
@Table(name = "users")
public class Users extends BaseEntity {
// ...
}
이렇게 상속만 해도 users 테이블에는 자동으로 created_at, updated_at 컬럼이 포함된다.
2-2. 생성일/수정일 자동 입력
그냥 필드만 두면 개발자가 직접 세팅해야 하지만, @CreatedDate와 @LastModifiedDate를 붙이면 JPA가 자동으로 값을 채워준다.
- 엔티티가 처음 저장될 때: created_at 자동 입력
- 엔티티가 수정될 때: updated_at 자동 갱신
개발자가 일일이 시간을 넣지 않아도 스프링이 알아서 현재 시간을 넣어준다.
3. BaseEntity가 동작하는 원리
이 자동 기록 기능은 내부적으로 "Auditing"이라는 기능을 통해 동작한다.
스프링이 엔티티의 생성/수정 이벤트를 감시하면서 필요할 때 LocalDateTime.now()를 넣어주는 것이다.
이 기능이 작동하려면 세 가지 조건이 필요하다.
3-1. @MappedSuperclass
해당 클래스의 필드를 자식 엔티티에 그대로 포함시켜라!
- BaseEntity 자체는 테이블로 만들지 않는다.
- 대신 Users, Product, Order 같은 엔티티들이 상속받을 때 created_at, updated_at 필드가 함께 매핑된다.
DB에 BaseEntity라는 테이블은 생기지 않는다.
3-2. @EntityListeners(AuditingEntityListener.class)
해당 클래스의 필드를 자동으로 감시하고, 엔티티 생성/수정 시점에 특정 동작을 수행해라!
- AuditingEntityListener는 엔티티가 저장되거나 업데이트될 때 호출된다.
- 그때 @CreatedDate, @LastModifiedDate가 붙은 필드를 찾아서 자동으로 값을 넣는다.
이게 바로 감사(Auditing) 기능이다.
3-3. @CreatedDate, @LastModifiedDate
해당 시점에 현재 시간을 기록해라!
- @CreatedDate: 최초 INSERT 시 현재 시간 자동 입력
- @LastModifiedDate: UPDATE 시 현재 시간 자동 갱신
save() 시 createdAt, update() 시 updatedAt이 자동 반영된다.
4. JPAConfig는 왜 필요한가
4-1. @EnableJpaAuditing이 Auditing 기능 활성화
BaseEntity에 @EntityListeners(AuditingEntityListener.class)를 붙였다고 자동으로 동작하는 건 아니다.
이 기능은 꺼져 있는 스위치라서 명시적으로 활성화해줘야 한다.
그걸 켜는 게 바로 JpaConfig다.
package com.serverCommerce.smzShop.common.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@Configuration
@EnableJpaAuditing
public class JpaConfig {
}
4-2. 내부 동작 원리
- 스프링이 프로젝트 시작 시 @EnableJpaAuditing을 찾는다.
- AuditingBeanFactoryPostProcessor가 등록된다.
- AuditingEntityListener가 엔티티 라이프사이클 이벤트를 구독한다.
- 엔티티가 저장(persist)되면 @CreatedDate 필드에 현재 시간 기록
- 엔티티가 수정(update)되면 @LastModifiedDate 필드에 시간 갱신
JpaConfig는 Auditing 기능을 전역적으로 활성화 하는 설정 파일이다.
이게 없으면 BaseEntity의 어노테이션이 있어도 createdAt, updatedAt이 null로 들어간다.
5. 전체 흐름
| 구분 | 설명 |
| @MappedSuperclass | BaseEntity를 테이블로 만들지 않고, 자식 엔티티에 필드만 상속 |
| @EntityListeners(AuditingEntityListener.class) | 엔티티 변경 감시 기능 연결 |
| @CreatedDate | 엔티티가 처음 저장될 때 자동 시간 기록 |
| @LastModifiedDate | 엔티티 수정 시 자동 시간 갱신 |
| @EnableJpaAuditing (in JpaConfig) | 위의 기능을 전체 프로젝트에 활성화 |
6. 실제 동작 예시
Users user = new Users("seoungmin", "1234");
userRepository.save(user);
저장 후 DB에는 이렇게 들어간다.
| username | password | created_at | updated_at |
| seoungmin | 1234 | 2025-10-18 14:35:00 | null |
그리고 나중에 수정하면
| username | password | created_at | updated_at |
| seoungmin | 12345 | 2025-10-18 14:35:00 | 2025-10-18 14:40:21 |
이렇게 updated_at이 자동으로 갱신된다.
7. 정리
- BaseEntity는 모든 엔티티의 공통 엔티티 역할을 한다.
- JPAConfig는 그 공통엔티티가 실제로 작동하게 하는 역할을 한다.
- 둘은 세트로 사용해야 자동 시간 기록(Auditing)이 완성된다.
BaseEntity로 공통 필드를 관리하고
JpaConfig로 Auditing 기능을 활성화하여 생성일/수정일을 자동으로 관리한다.
'공부일기.. > JPA' 카테고리의 다른 글
| [JPA] Spring Data JPA 페이징 (3/3) - 성능 최적화와 테스트 (0) | 2025.12.13 |
|---|---|
| [JPA] Spring Data JPA 페이징(2/3) - 실무 패턴과 동적 쿼리 (0) | 2025.12.11 |
| [JPA] Spring Data JPA 페이징 (1/3) - 기본 개념과 핵심 객체 (0) | 2025.12.08 |
| [JPA] JPA의 필수개념_2 (식별자 전략 (@Id, @GeneratedValue)) (1) | 2025.06.26 |
| [JPA] JPA의 필수개념_1 (JPA정의, Projection) (0) | 2025.06.26 |