Spring-data-envers

지능바바·2023년 5월 27일
0

실제 시스템을 운영하다보면 프로세스상에는 필요하지 않지만 운영의 편의성을 위해서 중요데이터의 변경사항을 history 테이블에 기록해 놓는 경우가 있다. 운영면에서는 분명 필요한 일이고, 많은 편의성을 제공해 주는 기능이기는 하지만 실제 개발하는 입장에서는 history를 관리하는 테이블의 변경이 있을때마다 함께 작업해 줘야 하기때문에 귀찮은 일인 경우가 많다.
이 때 spring-data-envers 를 이용하면 이 귀찮은 작업을 편하게 간단한 설정만 추가해서 처리할 수 있다.

1. spring-data-envers란?

hibernate-envers 를 스프링에서 사용하기 편하도록 랩핑한 프로젝트이다. 이 기능을 이용하면 중요 테이블의 history 기록을 간단하게 처리할 수 있다.

2. 기본 사용법

build.gradle 에 아래와 같이 spring-data-envers를 추가한다.

implementation 'org.springframework.data:spring-data-envers'

@SpringBootApplication이 있거나 @Configuration이 있는 설정 클래스에 아래의 어노테이션을 추가해 준다.

@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)

history를 관리할 대상이 되는 Entity에 아래와 같이 @Audited 어노테이션을 추가해준다.
참고로 @Audited는 클래스뿐 아니라 필드에도 설정 가능하다.

@Audited
@Getter @Setter
@ToString
@Entity
@Table(name = "category")
public class Category extends AuditEntity {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long categoryNo;
   private long parentCategoryNo;
   private String name;
}

그럼 이제 아래와 같이 2개의 테이블이 생성된다. 참고로 아래의 테이블 생성은 hibernate의 ddl-auto 가 creata 또는 update로 설정되어 있을때 자동으로 생성해 준 테이블이다.

CREATE TABLE `revinfo` (
   `rev` int NOT NULL AUTO_INCREMENT,
   `revtstmp` bigint DEFAULT NULL,
   PRIMARY KEY (`rev`)
 );
 
 CREATE TABLE `category_aud` (
   `category_no` bigint NOT NULL,
   `rev` int NOT NULL,
   `revtype` tinyint DEFAULT NULL,
   `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
   `parent_category_no` bigint DEFAULT NULL,
   PRIMARY KEY (`rev`,`category_no`),
   CONSTRAINT `FKc9m640crhsib2ws80um6xuk1w` FOREIGN KEY (`rev`) REFERENCES `revinfo` (`rev`)
 );

먼저 revinfo 는 envers가 동작했을때의 기록이다. rev 는 시퀀스번호이고, revtstmp는 기능이 동작했을때의 timestamp 값이다.
history 테이블은 위와같이 _aud가 테이블명 뒤에 붙는다.
rev 는 revinfo 테이블과의 연관관계를 가지는 키값이고, revtype 은 기록에 대한 타입니다.
revtype의 값은 아래와 같다.

0 : 입력
1 : 수정
2 : 삭제

3. 기타 설정

1. revinfo 테이블 수정

revinfo 테이블의 이름 및 컬럼명은 수정이 가능하다. 필요하면 컬럼을 더 추가할 수도 있다.
아래와 같이 @RevisionEntity 를 이용해서 revinfo 테이블 재정의 가능하다.

@Entity
@RevisionEntity
public class Revision {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @RevisionNumber
    private long revisionNo;
    
    @RevisionTimestamp
    private long createdAt;
}

2. @Audited, @NotAudited

  • @NotAudited : 이 어노테이션이 붙은 필드는 revision 대상에서 제외한다.
  • @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    @NotAudited와는 다르다. Entity에 설정된 다른 Entity는 기록을 원하지 않을경우 @NotAudited를 사용하면 된다. 하지만 이렇게 하면 해당 Entity에서 연관관계를 위해서 가지고 있는 필드도 제외되어 버린다. 그래서 연결된 Entity는 관리하지 않지만 연관관계의 키가되는 필드는 관리하고 싶을때 사용하면 된다.
@Audited
@Getter @Setter
@ToString
@Entity
@Table(name = "category")
public class Category extends AuditEntity {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long categoryNo;
   
   private long parentCategoryNo;
   
   private String name;
   
   @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
   @ManyToOne
   private Center center;
}

3. 그 외 여러가지 옵션설정

org.hibernate.envers.configuration.EnversSettings 파일을 열어보면 사용할 수 있는 옵션들이 정의되어 있는것을 확인 할 수 있다.
그 중 자주 사용될 만한 옵션 몇가지만 소개한다.

  • org.hibernate.envers.store_data_at_delete : 삭제될때 삭제 이전의 데이터를 기록한다. default는 false이고 PK 값과 rev, revtype 값만 기록한다.
  • org.hibernate.envers.audit_table_prefix : audit 테이블의 앞에 붙일 이름을 설정할 수 있다.
  • org.hibernate.envers.audit_table_suffix : audit 테이블의 뒤에 붙일 이름을 설정할 수 있다. default 는 _aud 이다.
  • org.hibernate.envers.revision_field_name : audit 테이블의 revinfo와의 관계컬럼명을 설정한다. default는 rev 이다.
  • org.hibernate.envers.revision_type_field_name : audit 테이블의 revison 타입 컬럼명을 설정한다. default는 revtype 이다.

0개의 댓글