티스토리 뷰

반응형

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/

https://hides.kr/1096

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/02   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
글 보관함