티스토리 뷰
1. Spring data envers
- hibernate 에서 만든 데이터 변경 이력을 로깅하기위한 라이브러리.
- 특정 테이블에 insert, update, delete 등의 이벤트 가 발생하면 다른 테이블에 같은 작업을 반복 해서 함으로서 자동으로 이력을 남길 수 있게 해주는 라이브러리
- JPA 로 구현되어있다
사용방법
1) 의존성추가
implementation 'org.hibernate:hibernate-envers'
2) @Audited 로 변경이력 저장할 테이블 생성
- 변경이력을 감지하고 싶은 엔티티에 @Audited 어노테이션을 추가한다.
@Entity
@Audited
public class Attendance {... }
=> Attendance_AUD 테이블이 자동 생성되서 변경이력을 확인할 수 있게된다.
=> Attendance_AUD 테이블에 추가되는 필드로 rev, revtype 이 있는데 rev는 작업번호, revtype은 작업내용이 어떤 작업이었는지를 의미한다.
rev : 작업번호 ( 동일한 트랜잭션에서 일어난 작업이면 모든 행이 같은 작업번호를 부여받음 )
revtype : 0 (생성) / 1 (수정) / 2 (삭제)
- 장점 : 쉽게 이력을 남길 수 있다. PK 가 복합키여도 문제없이 이력남기기가 가능하다.
- 단점: 이력을 똑같이 남길 수 있을 뿐, 타입, 필드명, 값을 변경할 수 없다. queryDSL 과 함께 사용시 호환이 되지 않는다.
2. Hibernate event listener
하이버네이트 이벤트 리스너를 이용해서 insert, update, delete 등의 이벤트가 불려질때 특정 함수가 실행되도록 할 수 있다. 이걸 이용해서 변경이력을 저장할 수 있다.
사용방법
1) 리스너를 만든다. PostInsert, PreInsert, PostUpdate, PreUpdate 등등 다양하게 존재한다. 필요한걸 implements 받아서 작성하면 된다.
@Component
@Slf4j
public class CustomPostInsertEventListener implements PostInsertEventListener {
@Lazy
@Autowired
AttendanceHistoryRepository attendanceHistoryRepository;
@Override
public void onPostInsert(PostInsertEvent event) {
if(event.getEntity() instanceof Attendance)
publishHistoryEvent(event);
}
private void publishHistoryEvent(PostInsertEvent event) {
log.info("onPostInsert!!" + event);
final Attendance origin = (Attendance) event.getEntity();
event.getSession().createNativeQuery(
"INSERT INTO attendance_history (user_name, attendance_type, date, start_datetime, end_datetime, history_type, create_datetime) " +
"VALUES (:user_name, :attendance_type, :date, :start_datetime, :end_datetime, :origin_id, :history_type, now())"
).setParameter("user_name", origin.getUserName())
.setParameter("attendance_type",origin.getAttendanceType().name())
.setParameter("date",origin.getDate())
.setParameter("start_datetime", origin.getStartDateTime())
.setParameter("end_datetime", origin.getEndDateTime())
.setParameter("history_type", "CREATE")
.setFlushMode(FlushMode.MANUAL)
.executeUpdate();
}
@Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return false;
}
}
2) 리스너를 등록한다.
@Component
@RequiredArgsConstructor
@Slf4j
public class HibernateListener {
private final EntityManagerFactory entityManagerFactory;
private final CustomPostInsertEventListener customPostInsertEventListener;
private final CustomPostUpdateEventListener customPostUpdateEventListener;
@PostConstruct
private void init() {
log.info("Initializing HibernateListener");
SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
registry.getEventListenerGroup(EventType.POST_INSERT).appendListener(customPostInsertEventListener);
registry.getEventListenerGroup(EventType.POST_UPDATE).appendListener(customPostUpdateEventListener);
}
}
장점: 이력을 남길때 추가 정보를 남기는 등 다양한 커스터마이징을 할 수 있다.
단점: 한 트랜잭션에서 Delete 와 Save 를 같이 하는 경우, 같은 트랜잭션에서 일어났다는 정보를 남길 수 없다.
근데 이거 이렇게 쓰라고 있는게 아닌 것 같다. hibernate event listener 는 객체를 저장하거나 수정할때 알림을 보낸다거나 로깅을 남긴다거나 하기위해 사용하는게 적절할듯.
참고
https://sehajyang.github.io/2020/04/15/springboot-envers-logging-for-revision/
'Spring' 카테고리의 다른 글
| Spring Ldap 공식문서 번역 (0) | 2022.08.03 |
|---|---|
| 스프링 배치 2장 - 스프링배치 (0) | 2022.03.13 |
| 스프링배치 1장 - 배치와 스프링 (1) | 2022.03.12 |
| 스프링 배치 2 - 시작하기 (0) | 2022.03.05 |
| 스프링 배치 1 - 개요 및 아키텍처 (0) | 2022.03.05 |