본문 바로가기
Spring/Spring JPA

JPA를 이용해 History 테이블 자동 생성하기

코동이 2021. 12. 14.

개요


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