본문 바로가기
ORM/Spring Data JPA

JPA Auditing

by 코딩하는 랄로 2024. 1. 17.
728x90

JPA  Auditing

JPA Auditing이란, Spring Data JPA가 CRUD 등 JPA를 이용한 작업을 할 때, Audit(감시) 기능을 위해 제공해주고 있다. 엔티티 객체가 영속성 컨텍스트에 저장, 수정, 삭제 등의 이벤트의 발생을 JPA Auditing에서 감시하고 있다가, 해당 이벤트가 발생하면 특정 로직을 처리할 수 있도록 해준다.

 

한마디로, javascript의 이벤트리스너의 기능을 JPA에서 사용할 수 있는 것이다. Entity에 대한 리스너는 따로 클래스 파일을 생성하여도 되지만 Spring Data JPA가 기본적으로 제공해주는 리스너를 사용하여도 된다.

 

이번 글에서는 Spring Data JPA가 제공해주는 JPA Auditing 을 사용하는 방법을 알아보겠다.

 

 

@EnableJpaAuditing

먼저 @SpringBootApplication 어노테이션이 붙은 application 클래스 파일에 다음 어노테이션을 붙인다.

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

 

해당 어노테이션을 붙이면, Spring Data JPA가 기본적으로 제공하는 JPA Auditing을 사용할 수 있게 된다.

 

 

@EntityListeners

이제 JPA Auditing을 사용할 수 있게 되었으니 감시 대상이 되는 Entity 개체를 지정해주고 해당 Entity 개체를 감시하는 Audition 클래스도 지정해주어야 한다. 이를 위한 어노테이션이 바로 @EntityListeners이다. ( 뒤에 's' 를 통해 알 수 있듯이 하나의 Entity에 여러개의 리스너가 등록 가능하다. )

@Data
@NoArgsConstructor
@RequiredArgsConstructor
@Entity
@EntityListeners(value = AuditingEntityListener.class)
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NonNull
    private String name;

    @NonNull
    private String address;

}

 

JPA 를 공부하면서 줄곧 사용해왔던 Student Entity에 엔티티 리스너를 등록하였다. @EnableJpaAuditing을 붙임으로써, AuditingEntityListener 를 사용할 수 있게 되었고 이를 등록해주었다.

 

 

이벤트 종류

이제 이벤트를 감시하기 위한 모든 준비는 끝났다. 이제는 AuditingEntityListener 가 감시할 수 있는 이벤트 종류에 대해 알아보자. JPA가 제공하는 이벤트 종류로는 다음의 7가지가 있다.

Event Description
@PrePersist persist() 메소드를 호출해서 엔티티를 영속성 컨텍스트에 관리하기 직전에 호출
@PreUpdate flush , commit을 통해 엔티티가 데이터베이스에서 수정되기 직전
@PreRemove 엔티티를 영속성 컨텍스트에서 삭제하기 직전
@PostPersist flush , commit을 통해 엔티티가 데이터베이스에서 저장된 직후
식별자 전략을 IDENTITY를 사용할 경우, persist()를 호출하면서 엔티티를 데이터베이스에 저장하기 때문에, persist()를 호출한 직후에 바로 PostPersist가 호출
@PostUpdate flush , commit을 통해 엔티티가 데이터베이스에서 수정된 직후
@PostRemove flush , commit을 통해 엔티티가 데이터베이스에서 삭제된 직후
@PostLoad 엔티티가 영속성 컨텍스트에 조회된 직 후, 또는 refresh를 호출한 후

 

이벤트를 사용할 때 주의할 점은 각각의 이벤트가 발생하는 지점이 영속성 컨텍스트인지, 데이터베이스인지를 알고 있어야 한다. 또한 같은 이벤트이더라도 PostPersist 처럼 호출 시점이 다를 수 있기 때문에 이 점 주의하여 사용하여야 한다.

 

 

예제

대부분 리스너를 사용하는 경우는, 데이터의 변화에 대한 기록을 남기거나 특정 데이터에 대한 간단한 로직을 처리하기 위해서 등 여러가지 이유가 있다.

 

이번 예제에서 다뤄볼 것은 Entity의 createdAt, regDate 등 시간 데이터 초기화이다. LocalDateTime은 @ColumnDefualt로 값을 넣어주지 못하기 때문에 이벤트 리스너를 통해 초기화를 해준 후 넣어주는 방식을 사용하기도 한다.

@Data
@NoArgsConstructor
@RequiredArgsConstructor
@Entity
@EntityListeners(value = AuditingEntityListener.class)
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NonNull
    private String name;

    @NonNull
    private String address;

    @Column(updatable = false)
    private LocalDateTime createdAt;

    @PrePersist
    public void PrePersist() {
        this.createdAt = LocalDateTime.now();
    }

}

 

컬럼 createdAt 은 생성된 날짜를 저장하는 컬럼이기 때문에 이후에 update 시에 값이 변경되지 않도록 칼럼의 updatable 속성을 false로 지정해주었고, Entity가 persist 되기 전에 createdAt 값을 지정해주는 것을 볼 수 있다. 해당 코드가 잘 동작하는지 보기 위해서 아래의 test 코드를 돌려보자.

@Test
void test() {
    Student student = new Student("kim", "email@email.com");
    studentRepository.save(student);  // INSERT

    System.out.println(studentRepository.findById(student.getId()).get());
}

 

결과를 보면 @PrePersist가 잘 동작하여 createdAt 이 초기화된 것을 볼 수 있다.

Hibernate: insert into Student (address,createdAt,name) values (?,?,?)
Hibernate: select s1_0.id, s1_0.address, s1_0.createdAt, s1_0.name from Student s1_0 where s1_0.id=?

Student(id=1, name=kim, address=email@email.com, createdAt=2024-01-17T15:10:23.204548)

 

 

 

728x90

'ORM > Spring Data JPA' 카테고리의 다른 글

EntityListener 다루기  (0) 2024.01.18
기본 CRUD - Create & Update  (0) 2024.01.16
기본 CRUD - DELETE  (1) 2024.01.16
기본 CRUD - READ  (0) 2024.01.16
JPA Repository - 개념  (0) 2024.01.15