포스트

2023-03-22-TIL

2023-03-22-TIL

Today I Learned

Configure Server

제목만 남아 있는 항목이다. 바로 전 TIL에서 비교한 Spring Cloud Config Server를 이어서 본 것으로 보인다. Config Server는 Git 같은 저장소에 둔 설정 파일을 /{application}/{profile}/{label} 형태의 HTTP 엔드포인트로 제공하고, 각 서비스는 시작할 때 자기 이름과 프로필에 맞는 설정을 받아 간다. 설정을 애플리케이션 밖 한곳에 모으고 변경 이력을 Git으로 관리하는 것이 목적이다.


@Configuration vs @Component

@Configuration 자체가 @Component로 메타 애너테이션되어 있어서, 둘 다 컴포넌트 스캔으로 빈이 된다. 차이는 그 안의 @Bean 메서드를 다루는 방식이다. Javadoc에 따르면 @Configuration의 proxyBeanMethods 기본값은 true이고, 이때 스프링은 런타임에 CGLIB 하위 클래스를 만들어 @Bean 메서드 호출을 가로챈다. 그래서 설정 클래스 안에서 다른 @Bean 메서드를 직접 호출해도 새 객체가 아니라 컨테이너의 싱글톤 빈이 반환된다(빈 간 참조). @Component 클래스나 proxyBeanMethods = false인 설정 클래스의 @Bean 메서드는 이런 가로채기 없이 평범한 팩터리 메서드로 처리되는데, 이를 “@Bean Lite Mode”라고 부른다.

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class AppConfig {
    @Bean
    public MemberRepository memberRepository() { return new MemoryMemberRepository(); }

    @Bean
    public MemberService memberService() {
        // @Configuration이면 컨테이너의 싱글톤 memberRepository가 주입된다
        // @Component였다면 호출할 때마다 새 객체가 만들어진다
        return new MemberService(memberRepository());
    }
}

CGLIB 하위 클래스를 만들어야 하므로 @Configuration 클래스와 그 @Bean 메서드는 final일 수 없다. 빈 간 참조가 필요 없다면 proxyBeanMethods = false로 프록시 생성을 생략할 수 있고, Spring Boot의 자동 설정 클래스들이 이렇게 한다.

  • https://blog.naver.com/sthwin/222131873998
  • https://stackoverflow.com/questions/39174669/what-is-the-difference-between-configuration-and-component-in-spring

Articles

GeekNews에 올라온 Bluesky 소개 글이다. 트위터(잭 도시)가 발표하고 자금을 댄 개방형, 분산형 소셜 미디어 프로젝트로, 처음 내세운 목표는 트위터가 이 표준의 클라이언트가 되는 것이었다. 연합형(federated) 구조의 AT Protocol(Authenticated Transfer Protocol)을 쓰고, 사용자가 소유한 도메인 이름을 핸들로 쓸 수 있으며, 글이 올라온 시점에는 초대 기반 비공개 베타였다.

  • https://news.hada.io/topic?id=8755&utm_source=slack&utm_medium=bot&utm_campaign=T74H5245A

이력유형

이력 데이터의 종류

발생 이력 데이터

⇒ 어떤 데이터가 발생할 때마다 이력 정보를 남겨야 할때 예) 스포츠 데이터 (실시간 중계)

변경 이력 데이터

⇒ 데이터가 변경될 때마다 변경 전과 후의 차이를 확인해야 할때 예) 리뷰 수정 전 후를 비교하고 싶을 때

진행 이력 데이터

⇒ 업무의 진행에 따라 데이터의 이력 정보를 남겨야 할 때 예) 택배

이력 테이블 설계

참고한 글은 이력을 저장하는 방식을 두 가지로 나눈다. 원본 테이블에 이력을 함께 두는 방식은 수정이 생기면 새 레코드를 만들고 이전 레코드를 이력으로 취급한다. 원본과 이력을 같이 조회하는 경우가 많을 때 유리하지만 테이블의 성격이 흐려진다. 이력 테이블을 분리하는 방식은 수정이 생길 때마다 변경 전 상태를 스냅숏으로 이력 테이블에 쌓고 원본은 갱신한다. 원본과 이력을 같이 볼 일이 드물거나 하위 엔티티가 많을 때 유리하다.

시점을 기록하는 방식도 둘이다.

  • 점이력: 변경이 일어난 시작 시점만 기록한다. 쌓기는 쉽지만 “특정 날짜의 상태”를 찾으려면 그 날짜 이전 중 가장 최근 레코드를 찾아야 해서 조회가 비효율적이다.
  • 선분이력: 시작 시점과 종료 시점을 함께 기록한다. 새 이력을 넣을 때 이전 레코드의 종료 시점을 닫아야 하지만, 시작 <= 기준일 < 종료 조건 하나로 특정 시점의 상태를 바로 찾을 수 있다.

삭제도 이력 관점에서 나뉜다. 레코드를 실제로 지우는 하드 삭제는 빠르고 단순하지만 이력이 남지 않고, 삭제 여부 컬럼만 바꾸는 소프트 삭제는 복구와 과거 조회가 쉽지만 모든 조회에서 상태를 확인해야 한다.

  • https://dataonair.or.kr/db-tech-reference/d-lounge/expert-column/?mod=document&uid=52906#:~:text=%EC%9D%B4%EB%A0%A5%EC%9D%80%20%EC%8B%9C%EA%B0%84%EC%97%90%20%EB%94%B0%EB%9D%BC,%EA%B0%80%20%EB%B9%88%EB%B2%88%ED%95%98%EA%B2%8C%20%EC%9D%B4%EC%9A%A9%EB%90%9C%EB%8B%A4.
  • https://12bme.tistory.com/200
  • https://velog.io/@dankim/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9D%B4%EB%A0%A5-%EA%B4%80%EB%A6%AC

이력테이블에 자동으로 데이터 쌓기 in JPA: Envers

Hibernate Envers는 엔티티 변경 이력을 자동으로 쌓아 주는 모듈이다. Baeldung 설명대로 엔티티에 @Audited를 붙이면(특정 컬럼에만 붙일 수도 있다) 엔티티명_AUD 이력 테이블이 생기고, 감사 대상 필드와 함께 REV(리비전 번호)와 REVTYPE(0 추가, 1 수정, 2 삭제)이 기록된다. 리비전마다의 시각은 별도의 REVINFO 테이블에 REV, REVTSTMP로 남고, 각 이력 테이블의 REV가 이를 참조한다. 연관 엔티티도 함께 이력을 남기려면 그쪽에도 @Audited를 붙여야 한다.

Spring Data Envers를 쓰면 저장소에 RevisionRepository<Person, Long, Long>을 추가로 상속해 리비전 목록이나 특정 리비전의 엔티티를 조회하는 메서드를 바로 쓸 수 있다. 위의 분류로 보면 이력 테이블을 분리하는 스냅숏 방식이다. 누가, 언제 만들고 바꿨는지만 필요하다면 Envers 대신 Spring Data JPA의 @CreatedDate, @LastModifiedDate(Auditing)로 충분하다.

1
2
3
4
5
6
7
8
9
10
@Entity
@Audited
public class Person {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

interface PersonRepository
        extends CrudRepository<Person, Long>, RevisionRepository<Person, Long, Long> {}
  • https://compunication.tistory.com/27
  • https://www.baeldung.com/database-auditing-jpa
  • https://gist.github.com/dlxotn216/94c34a2debf848396cf82a7f21a32abe
  • https://www.linkedin.com/pulse/history-audit-javajpahibernate-entity-classes-shubham-ambatkar?trk=public_profile_article_view
  • https://sehajyang.github.io/2020/04/15/springboot-envers-logging-for-revision/
  • https://stackoverflow.com/questions/57676086/how-to-implement-history-data-changes-with-spring-boot-spring-data
  • https://levelup.gitconnected.com/manage-a-history-of-domain-model-changes-with-spring-609d2613fc7d
  • https://escapefromcoding.tistory.com/550
  • https://reachmnadeem.wordpress.com/2021/06/04/maintaining-data-revision-history-with-spring-data-envers/
  • https://docs.spring.io/spring-data/envers/docs/current/reference/html/
참고한 자료외부 출처 5

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다