2012-07-17 4 views
2

프레임 워크 : 봄 3 최대 절전 모드 (3)와최대 절전 모드. 법인 변경 개정 역사

데이터베이스 : 오라클 11

요구 사항 : 이벤트 개체가됩니다 우리의 응용 프로그램입니다. 이러한 각 Event 객체는 Entity 속성 집합 (테이블 열)의 캡슐화입니다. 따라서 Entity가 시스템에서 업데이트 될 때마다 엔티티에 대한 변경 사항이 Event 객체의 일부인지 확인해야하며, 그렇다면이 정보를 데이터베이스에 저장해야합니다. 실제 변화.

솔루션 (내가 아는) :

  1. 가 최대 절전 모드 Envers 같은 만발한 감사 프레임 워크를 사용하고 내가 원하는 것을 달성하기 위해, 감사 테이블 쿼리 기능의 주위에 작은 래퍼를 작성합니다. 한 가지 질문은 최대 절전 모드 Envers는 두 가지 수정 버전간에 변경된 사항을 제공하는 쉬운 방법이 있는지입니다.

  2. 사용자 정의 주석을 사용하여 이벤트에 속하는 속성을 표시하고 AOP를 사용하여 저장 조작의 일부로 이러한 속성의 변경 사항을 모니터하고 사용자 정의 쓰기 조작을 호출하십시오.

나는 두 번째 아이디어를 더 좋아합니다.

최대한 빨리 의견을 공유해주세요. 이런 종류의 문제에 대한 기존 솔루션이 있습니까?

답변

2

나는 프로젝트 전에 저장하기 전에 복잡한 객체 그래프의 스냅 샷을 찍을 것을 가정합니다. 난 적용한

용액 1)는 오리지널, 무시 무효화 같은 특정 속성 정의 주석 @Archivable 개발 오브젝트의 복제를 생성하고 동일한 테이블에 삽입 setArchiveFlag

hiberante 깊은 클론 업체 유틸리티 기록

2)이다. deep cloner는 간단한 트릭을 검색하고 객체를 deslite 처리하여 새 인스턴스를 만든 다음 id 및 version을 null로 설정합니다.

3) 엔티티 인터셉터에서 아카이브 날씨를 결정하기 위해 cloner 유틸리티를 사용했습니다.

아래 코드 중 일부입니다.

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.TYPE }) 
public @interface Archivable { 

    /** This will mark property as null in clone */ 
    public String[] nullify() default {}; 

    /** 
    * If property is archivable but not from enclosing entity then specify as 
    * ignore. 
    */ 
    public String[] ignore() default {}; 

    /** 
    * sets original reference to clone for back refer data. This annotation is 
    * applicable to only root entity from where archiving started. 
    * 
    * @return 
    */ 
    public String original() default ""; 

    /** 
    * if marks cloned entity to archived, assumes flag to be "isArchived". 
    * @return 
    */ 
    public boolean setArchiveFlag() default false; 
} 


@Component 
public class ClonerUtils { 

    private static final String IS_ARCHIVED = "isArchived"; 
    @Autowired 
    private SessionFactory sessionFactory; 

    public Object copyAndSave(Serializable obj) throws Exception { 
     List<BaseEntity> entities = new ArrayList<BaseEntity>(); 
     Object clone=this.copy(obj,entities); 
     this.save(clone, entities); 
     return clone; 
    } 

    public Object copy(Serializable obj,List<BaseEntity> entities) throws Exception{ 
     recursiveInitliaze(obj); 
     Object clone = SerializationHelper.clone(obj); 
     prepareHibernateObject(clone, entities); 
     if(!getOriginal(obj).equals("")){ 
      PropertyUtils.setSimpleProperty(clone, getOriginal(obj), obj); 
     } 
     return clone; 
    } 


    private void save(Object obj,List<BaseEntity> entities){ 
     for (BaseEntity baseEntity : entities) { 
      sessionFactory.getCurrentSession().save(baseEntity); 
     } 
    } 

    @SuppressWarnings("unchecked") 
    public void recursiveInitliaze(Object obj) throws Exception { 
     if (!isArchivable(obj)) { 
      return; 
     } 
     if(!Hibernate.isInitialized(obj)) 
      Hibernate.initialize(obj); 
     PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
     for (PropertyDescriptor propertyDescriptor : properties) { 
      Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName()); 
      if (origProp != null && isArchivable(origProp) && !isIgnore(propertyDescriptor, obj)) { 
       this.recursiveInitliaze(origProp); 
      } 
      if (origProp instanceof Collection && origProp != null) {    
       for (Object item : (Collection) origProp) { 
        this.recursiveInitliaze(item); 
       } 
      } 
     } 
    } 


    @SuppressWarnings("unchecked") 
    private void prepareHibernateObject(Object obj, List entities) throws Exception { 
     if (!isArchivable(obj)) { 
      return; 
     } 
     if (obj instanceof BaseEntity) { 
      ((BaseEntity) obj).setId(null); 
      ((BaseEntity) obj).setVersion(null); 
      if(hasArchiveFlag(obj)){ 
       PropertyUtils.setSimpleProperty(obj, IS_ARCHIVED, true); 
      } 
      entities.add(obj); 
     } 
     String[] nullifyList = getNullifyList(obj); 
     for (String prop : nullifyList) { 
      PropertyUtils.setProperty(obj, prop, null); 
     } 
     PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
     for (PropertyDescriptor propertyDescriptor : properties) { 
      if (isIgnore(propertyDescriptor, obj)) { 
       continue; 
      } 
      Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());   
      if (origProp != null && isArchivable(origProp)) { 
       this.prepareHibernateObject(origProp, entities); 
      } 
      /** This code is for element collection */ 
      if(origProp instanceof PersistentBag){ 
       Collection elemColl=createNewCollection(origProp); 
       PersistentBag pColl=(PersistentBag) origProp; 
       elemColl.addAll(pColl.subList(0, pColl.size())); 
       PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), elemColl); 
       continue; 
      } 
      if (origProp instanceof Collection && origProp != null) { 
       Collection newCollection = createNewCollection(origProp); 
       PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), newCollection); 
       for (Object item : (Collection) origProp) { 
        this.prepareHibernateObject(item, entities); 
       } 
      } 
     } 
    } 



    @SuppressWarnings("unchecked") 
    private Collection createNewCollection(Object origProp) { 
     try { 
      if(List.class.isAssignableFrom(origProp.getClass())) 
       return new ArrayList((Collection)origProp); 
      else if(Set.class.isAssignableFrom(origProp.getClass())) 
        return new HashSet((Collection)origProp); 
      else{ 
       Collection tempColl=(Collection) BeanUtils.cloneBean(origProp); 
       tempColl.clear(); 
       return tempColl; 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return new ArrayList();  
    } 

    private boolean isIgnore(PropertyDescriptor propertyDescriptor,Object obj){ 
     String propertyName=propertyDescriptor.getName(); 
     String[] ignores=getIgnoreValue(obj); 
     return ArrayUtils.contains(ignores, propertyName); 
    } 

    private String[] getIgnoreValue(Object obj) { 
     String[] ignore=obj.getClass().getAnnotation(Archivable.class).ignore(); 
     return ignore==null?new String[]{}:ignore; 
    } 

    private String[] getNullifyList(Object obj) { 
     String[] nullify=obj.getClass().getAnnotation(Archivable.class).nullify(); 
     return nullify==null?new String[]{}:nullify; 
    } 

    public boolean isArchivable(Object obj) { 
     return obj.getClass().isAnnotationPresent(Archivable.class); 
    } 


    private String getOriginal(Object obj) { 
     String original=obj.getClass().getAnnotation(Archivable.class).original(); 
     return original==null?"":original; 
    } 

    private boolean hasArchiveFlag(Object obj) {   
     return obj.getClass().getAnnotation(Archivable.class).setArchiveFlag(); 
    } 

    @SuppressWarnings({ "unchecked", "unused" }) 
    private Collection getElemColl(Object obj, Object origProp) { 
     Collection elemColl=createNewCollection(origProp); 
     for (Object object : (Collection)origProp) { 
      elemColl.add(object); 
     } 
     return elemColl; 
    } 

    @SuppressWarnings("unused") 
    private boolean isElementCollection(Object obj, String name) { 
     try { 
      Annotation[] annotations=obj.getClass().getDeclaredField(name).getAnnotations(); 
      for (Annotation annotation : annotations) { 
       if(annotation.annotationType() == ElementCollection.class) 
        return true; 
      } 
     } catch (Exception e) { 
      e.printStackTrace();    
     } 
     return false; 
    } 
    }