[삽질] 약관 테이블 Entity 아커스(캐시)에 적용까지의 오류들 정리
내가 개발을 진행했던 프로젝트 중에서 가장 버그가 많았고, 정상적으로 배포하기까지 품이 많이 들었던 작업이였던 거 같다.
사실, 정리하고 보니까 별 것 쉬운 것 같지만 오류를 만났을 때 당시는 되게 해결하기 위해 많이 검색하고 고민했었다. 동일한 실수를 하지 않기 위해서 오류를 시간 순서대로 정리해본다.
설명에 들어가기 앞서 알아야 할 것들
- 내가 적용하고자 하는 약관 테이블의 구조는
약관(N)
⇆약관 그룹(N)
⇆약관 루트(N)
의 구조를 가지고 각각 N:N 관계이다. - N:N을 1:N 연관관계로 만들기 위해서 각 테이블 사이에 maps table을 만들었다.
약관(1)
⇆약관 그룹 약관 Maps(N)
⇆약관 그룹(1)
⇆약관 루트 & 약관 그룹 Maps(N)
⇆약관 루트(1)
약관 그룹
entity에는약관 그룹 약관 Maps
과약관 루트 & 약관 그룹 Maps
가 존재한다.
- 아커스(캐시)에 적재할 때는 객체를 json string으로 변환한다.
- 아커스(캐시)는 cache miss 할 때 DB에서 조회한 뒤 캐시에 적재한다.
- 아커스(캐시)는 transaction이 끝나고 캐시에 적재한다.
개발 내용: 약관 Repository(DB layer) 앞에 아커스 cahce layer를 둬서 DB 전에 캐시를 먼저 사용하도록 한다.
1. DB layer에 아커스 캐시 layer 적용
map 형태로 자주 사용되는 key를 기준으로 캐시에 넣어서 DB가기전에 조회함.
없으면, DB 조회 후 cache에 적재
2. 캐시 적용 후 테스트 코드 작성
양방향 연관 관계(termsGroupTermsMap) 때문에 테스트 코드에서 lazy로딩 오류가 발생함.
FetchType을 EAGER
로 추가하던가, Test 코드에 @Transactional
어노테이션을 붙이면 됨.
3. 모든 Entitiy 연관관계를 fetchType EAGER로 변경
@Transactional
과 FetchType.EAGER
중에서 cache 적재해서 효율 올릴려면 미리 조회해서 가지고 있는게 좋다고 생각이 되어, 모든 설정을 EAGER로 변경.
4. 약관 그룹에 있는 약관 / 약관 루트와의 연관관계 때문에 EAGER로 설정을 불가
5. fetchType LAZY로 원복 및 Test 코드에 @Transactional을 붙이는 방식으로 변경했다.
제대로 적재되는 지 두번 호출해서 아커스 hit 되서 가져오는 지는 테스트 코드에서 알 수는 없지만 hit하지 않았을 때 DB에서 정상적으로 가져오는 것까지만 테스트 진행.
6. 양방향 연관관계 entity 때문에 양방향 순환참조 문제(*Circular reference) 발생
7. 양방향으로 매핑되어있는 객체에 대해서 무한루프로 서로를 참조 문제가 발생하고 스택오버플로우
아커스 적재하는 게 문제라긴보단 아커스 적재 시 ObjectMapper가 Json 형태로 객체를 변환 시키는 과정에서 양방향으로 매핑되어있는 객체에 대해서 JSON 타입에 대한 무한루프문제가 발생하고 스택오버플로우가 발생
양방향 순환참조 해결방법 출처
8. 아커스가 정상적으로 조회되지 않음.
위처럼 양방향 순환참조 문제를 해결 5의 b로 설정한 뒤 문제는 @EqualsAndHashCode로 실제 terms가 같은 지 조회할 때 객체 주소가 아닌 객체 내용을 보고 같으면 동일한 객체라고 판단하는데 @EqualsAndHashCode에 Maps를 제외시키지 않아서 TermsGroupTermsMap도 내용 비교를 했음. 정상적으로 조회가 되지 않았다. Maps에 @EqualsAndHashCode가 안 붙어있던거는 아니고 비교 시 null 경우가 있어서 정상적으로 비교되지 않았던거 같음. @EqualsAndHashCode 안의 하위 객체도 전부 @EqualsAndHashCode가 붙어있어야 정상적으로 객체주소가 아닌 필드 값으로 비교를 함.
- @EqualsAndHashCode 에서 exclude로 TermsGroupTermMaps 제외 시켰다.
댓글남기기