• Home
  • About
    • Mayaul photo

      Mayaul

      hello woooooorld.

    • Learn More
    • Facebook
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

entity 의 변경사항 체크

01 Jun 2020

Reading time ~2 minutes

들어 가면서

  • 우리가 envers 를 이용하면, entity 의 변경이력을 관리를 손쉽게 할 수 있습니다.
  • 하지만, 변경된 필드에 대해서만 별도로 이력을 저장을 하고 싶다면 envers 를 이용해서는 한계가 있습니다.
  • envers 를 이용해서, audit table 에서 특정 필드의 변경사항만 조회를 할 수는 있지만,
    • 이 조회를 API로 구현을 해야하고, 그 API 가 사용자에게 노출이 될 목적의 데이터라면 별도의 데이터를 쌓는것이 DB에 과하게 부하를 줄 수 있어 제외하였습니다.

using Interceptor

  • Interceptor 추가
    public class Interceptor extends EmptyInterceptor {
     @Override
     public boolean onFlushDirty(Object entity,
                                 Serializable id,
                                 Object[] currentState,
                                 Object[] previousState,
                                 String[] propertyNames,
                                 Type[] types)
         throws CallbackException {
    
         if (entity instanceof Entity) {
             log.info("[Interceptor] Entity 변경 되었습니다. property: {}, prev: {}, current: {}", propertyNames, previousState, currentState);
         }
    
         return false;
     }
    }
    
  • interceptor 설정하기
    • application.yaml (full package 경로를 포함한 class path)
        spring.jpa.properties.hibernate.session_factory.interceptor: com.github.mayaul.Interceptor
      
  • 한계점
    • checking 해야하는 field 추가/변경/삭제 시에 관리비용 많이 들어갈 수 있습니다.
    • 뭐가 변경이 되었는지를 확인할려면, propertyNames 로 모든 field 를 조회를 해야합니다.

using Listener

  • Listener 추가
    @Component
    public class EntityUpdateEventListener implements PostUpdateEventListener {
      @Override
      public void onPostUpdate(PostUpdateEvent event) {
          if (event.getEntity() instanceof Entity) {
    
              log.info("[Interceptor] Entity 변경 되었습니다. event: {}", event);
          }
      }
    
      @Override
      public boolean requiresPostCommitHanding(EntityPersister persister) {
          return false;
      }
    }
    
  • Listener 등록
    @Component
    public class HibernateListenerConfig {
    
      private final EntityUpdateEventListener entityUpdateEventListener;
    
      @PersistenceUnit
      private EntityManagerFactory emf;
    
      public HibernateListenerConfig(EntityUpdateEventListener entityUpdateEventListener) {
          this.entityUpdateEventListener = entityUpdateEventListener;
      }
    
      @PostConstruct
      protected void init() {
          SessionFactoryImpl sessionFactory = emf.unwrap(SessionFactoryImpl.class);
          EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
          registry.getEventListenerGroup(EventType.POST_UPDATE).appendListener(entityUpdateEventListener);
      }
    }
    
  • PostUpdateEvent#getDirtyProperties 에 변경된 필드가 있습니다.
    event.getOldState()[event.dirtyProperties[0]]
    event.getState()[event.dirtyProperties[0]]
    event.getOldState()[event.dirtyProperties[1]]
    event.getState()[event.dirtyProperties[1]]
    

    이렇게 조회하면 변경된 필드에 대해서만 이전과 현재값을 알 수 있습니다.

    • event.dirtyProperties 에는 변경된 필드의 순서값(field type integer)이 들어가 있습니다.
      • entity 의 순서가 변경이 된다면 동일한 field 이지만, 체크를 다시 못하게 될 수 있습니다.
      • 이때, 아래와 같이 코드를 작성하면 필드의 이름을 이용해서 해당 필드의 값이 변경이 되었는지 확인 할 수 있습니다.
          event.getPersister().getPropertyNames()[dirtyProperty].equals(CHECK_FIELD)
        

마무리

  • 지금까지 Envers 와는 다르게, Entity 의 특정 필드의 변경사항만 체크를 할 수있는 방법을 알아 보았습니다.
    • 이렇게 하면 entity 의 특정 필드 값만 변경이 되었을 때, 별도의 table 에 변경내역을 저장을 할 수 있습니다.
    • entity 의 특정 필드 변경내역만 제공의 필요성이 있을 때, 유용하게 쓸 수 있을 것 같습니다.
  • 감사합니다.

참고 자료

https://kwonnam.pe.kr/wiki/java/hibernate/interceptor
https://stackoverflow.com/questions/43472893/hibernate-envers-get-only-changed-fields
https://vladmihalcea.com/hibernate-event-listeners



hibernatehibernate historyhibernate entity modify check Share Tweet +1