개요
JPA를 이용해 생성시간, 수정시간, 생성자, 수정자를 자동으로 등록하는 방법을 공부했었습니다. 이번에는 JPA를 이용해서 특정 테이블을 저장할 때 히스토리를 같이 저장하도록 하겠습니다.
history 테이블을 과거 이력을 확인할 때 용이합니다. 알림톡을 보냈거나, 사용자 권한이 변경된 기록들이 남아 있어 과거 이력을 추적할 수 있습니다. 만약 순수하게 만들어준다면 같은 데이터를 2번이나 save()해야 하는 번거로움이 있습니다. 하지만 @PrePersist, @PreUpdate를 사용하면 저장과 수정이후 JPA동작을 추가할 수 있습니다.
코드 작성하기
1. ApplicationContext로 직접 빈을 호출하는 유틸 클래스를 만든다.
Entity에 Repository 주입이 불가능합니다. 따라서 Entity에 @Autowired를 사용할 수 없고 직접 ApplicationContext를 통해서 Repository를 호출해야 합니다. ApplicationContext로 직접 빈을 호출하여 사용할 수 있습니다. 따라서 Repository Bean을 호출하는 함수를 생성합니다. 이 클래스를 통해서 Entiy에서 Repository를 직접 호출 할 수 있습니다.
@Component
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanUtil.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
}
ApplicationContextAware를 상속하면 ApplicationContext를 호출할 수 있습니다. static <T> T getBean(Class<T> clazz) 함수는 static이므로 어느곳에서든지 직접 빈을 호출할 수 있다. 어떠한 리턴형도 받을 수 있도록 반환형을 T로 합니다.
2. 자동으로 history 테이블에 저장할 데이터를 추가한다.
public class AccountEntityListener {
@PrePersist
@PreUpdate
public void prePersistAndPreUpdate(Object o) {
AccountHistoryRepository accountHistoryRepository = BeanUtil.getBean(AccountHistoryRepository.class);
Account account = (Account) o;
AccountHistory accountHistory = AccountHistory.builder()
.name(account.getName())
.email(account.getEmail())
.nickname(account.getNickname())
.password(account.getPassword())
.deleted(account.isDeleted())
.build();
accountHistoryRepository.save(accountHistory);
}
}
@PrePersist, @PreUpdate
@PrePersist는 JPA가 persist하기 직전에, @PreUpdate는 JPA가 update하기 직전에 해당 메서드가 동작하도록 합니다.
BeanUtil에 정의해둔 getBean()함수를 통해 계정 히스토리 저장소 빈을 가져옵니다.
prePersistAndPreUpdate(Object o)
매개변수의 o는 Account가 저장될 때 객체 정보를 담고 있습니다. 해당 정보를 이용해서 계정 히스토리 테이블에 저장할 값을 호출하면 된다. 저장 로직은 일반 저장소의 저장로직과 똑같습니다
3. EntityListener를 등록하여 실제로 히스토리 테이블 자동 저장을 설정한다.
...
@EntityListeners(value = AccountEntityListener.class)
public class Account extends BaseTimeEntity {
정리
이상으로 히스토리 테이블 자동 저장을 알아보았습니다. Entity에 Repository가 주입이 안되므로 직접 ApplicationContext를 호출하는 코드를 작성했습니다. 또한, 저장, 수정 시 해당 엔티티를 감시해서 히스토리 테이블에 그대로 정보를 넣어주도록 했습니다. 이를 통해 서비스로직에서 반복적인 작업이 줄어듭니다. 현재 Account에만 적용을 했지만, 상황에 따라 적절하게 사용하면 많은 편리함을 가져다줍니다.
'Spring > Spring JPA' 카테고리의 다른 글
OSIV (0) | 2022.10.01 |
---|---|
일반 Join vs Fetch Join (0) | 2022.06.29 |
페치 조인 ( fetch join ) - 2 (0) | 2021.10.06 |
페치 조인 ( fetch join ) -1 (0) | 2021.10.05 |
N + 1 문제 (0) | 2021.09.30 |