JPA Auditing이란?
Java에서 ORM 기술인 JPA를 사용하여 도메인을 관계형 데이터베이스 테이블에 매핑할 때 공통적으로 도메인들이 가지고 있는 필드나 컬럼들이 존재한다. 대표적으로 생성일자, 수정일자, 식별자 같은 필드 및 컬럼이 있다.
도메인마다 공통으로 존재한다는 의미는 결국 코드가 중복된다는 말이며 중복을 제거하는 것은 프로젝트의 유지보수적 측면에서 핵심적인 사양이다.
데이터베이스에서 누가, 언제하였는지 기록을 잘 남겨놓아야 한다. 그렇기 때문에 생성일, 수정일 컬럼은 대단히 중요한 데이터다.
그래서 JPA에서는 Audit이라는 기능을 제공하고 있다. Audit은 감시하다, 감사하다라는 뜻으로 Spring Data JPA에서 시간에 대해서 자동으로 값을 넣어주는 기능. 도메인을 영속성 컨텍스트에 저장하거나 조회를 수행한 후에 update를 하는 경우 매번 시간 데이터를 입력하여 주어야 하는데, audit을 이용하면 자동으로 시간을 매핑하여 데이터베이스의 테이블에 넣어줄 수 있다.
의존성 추가
기본적으로 스프링 부트에서 gradle로 의존성을 관리하게 될 경우 spring-boot-starter-data-jpa만 추가해도 Audit을 하는데는 문제가 없다. 이 말은 Spring-Data-JPA 안에 해당 기능이 있다는 말과 같다.
dependencies {
...
//SpringBoot JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
...
}
Java
복사
해당 기능을 사용 할 실제 Entity 클래스 파일, Timestamped.java
@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;
}
Java
복사
위 엔티티 클래스의 Audit관련 주요 어노테이션의 설명은 다음과 같다.
@MappedSuperclass | JPA Entity 클래스들이 해당 추상 클래스를 상속할 경우 createDate, modifiedDate를 컬럼으로 인식 |
@EntityListeners(AuditingEntityListener.class | 해당 클래스에 Auditing 기능을 포함 |
@CreatedDate | Entity가 생성되어 저장될 때 시간이 자동 저장 |
@LastModifiedDate | 조회한 Entity의 값을 변경할 때 시간이 자동 저장 |
클래스의 상속
해당 엔티티 클래스는 시간을 기록하는 필드만으로 구성되어 있기 때문에, 프로젝트 내의 본 엔티티에서는 상속을 통해서 해당 필드들을 사용할 수 있어야 한다.(== 포함되어야 한다.)
예를 들어 상품과 관련된 어떠한 프로젝트의 주요 엔티티인 Product 클래스가 있다고 가정하면, 상품명, 상품 내용, 가격 등 필드들이 있을 것이다. 여기에 상품을 등록한다면 등록 시간, 수정 시간이 필요하기 때문에 위 Timestamped.java의 멤버(필드)를 상속받아서 상품 안에 멤버로 포함시켜야 한다.
@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Getter
@Setter
@Table(name = "product") // 매핑할 테이블의 이름을 지정
@NoArgsConstructor
public class Product extends Timestamped { // <- Audit Timestamp 멤버 상속
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String image;
@Column(nullable = false)
private String link;
@Column(nullable = false)
private int lprice;
@Column(nullable = false)
private int myprice;
public Product(ProductRequestDto requestDto) {
this.title = requestDto.getTitle();
this.image = requestDto.getImage();
this.link = requestDto.getLink();
this.lprice = requestDto.getLprice();
}
public void update(ProductMypriceRequestDto requestDto) {
this.myprice = requestDto.getMyprice();
}
}
Java
복사
Product는 Timestamp로부터 상속 받았기 때문에, Timestamp의 createAt, modifiedAt이라는 시간과 관련된 필드를 갖게 된다.
JPA Audit 활성화 시키기
위 처럼 상속으로 주요 엔티티가 시간과 관련된 멤버를 갖게 된다 하더라도, Spring 자체에서 저 클래스들의 관계를 인지하도록 알려야 한다.
@EnableScheduling //<- 스케쥴러 활성화하려면 추가
@EnableJpaAuditing //<- JPA Audit 활성화하려면 추가
@SpringBootApplication
public class MyselectshopApplication {
public static void main(String[] args) {
SpringApplication.run(MyselectshopApplication.class, args);
}
}
Java
복사
프로젝트의 메인 메소드라 할 수 있는 시작부(init) 클래스의 상단에 @EnableJpaAuditing 어노테이션을 추가하여 Timestamped, Product 클래스간의 JPA Audit 관계가 활성화 되며, 또한 Audit관련 메서드들도 모두 활성화 되게 되어 정상 작동하게 된다.