엔티티 클래스에 @Audited
만 붙여주면 데이터베이스 변경 이력 저장 등 감사(audit) 기능을 제공해주는 Hibernate Envers를 쓰고 있다.
감사 기능은 좋긴 한데 @Audited
가 붙은 이후에는 해당 엔티티 테이블 스키마에 변경이 생기면 Envers가 감사용으로 사용하는 테이블인 _aud
테이블에도 반영해줘야 한다. 예전에 이거 안 해줘서 런타임 오류가 발생했었는데 알고 보면 간단하지만 모르는 상태에서 원인 찾는 건 쉽지 않다.
여튼 오늘은 아래와 같은 에러를 만났다.
Could not locate getter method for property [클래스이름#필드이름]
원래 #
다음에는 필드 이름이 오는지라 null 나오기 쉽지 않은데 null 이라니.. 살짝 느낌이 서늘했는데 역시나 검색해봐도 안 나오는..
결국 이 시간까지 매달려서 해결..
@Audited
가 붙은 User 엔티티가 있고, 보안 각서 비슷한 NDA 엔티티가 있다. NDA에는 @Audited
가 없다.
연관 관계는 일대일 단방향(NDA -> User)이다.
이 상태에서 User를 저장하면 그냥 User 엔티티의 저장은 잘 되는데, Commit 전에 Envers의 감사 기능 동작 중에 위와 같이 에러가 난다.
아래와 같이 beanName이 null이기 때문에 발생하는 에러다.
하지만 왜 null 인 값이 저기 들어가는지, 또 null 인 값이 안 들어가게 하려면 어찌해야 되는지 쉽게 알 방법이 없어서 이번에도 감에 의존하는 트라이얼 앤 에러 꽃삽질 시작..
이리저리 해보다가 답을 찾고 나서 알게 된 원인은.. 연관 관계였다.
@Audited
가 붙어있는 User를 저장하는데 User는 NDA를 모르고,- NDA는 User를 알지만 NDA에는
@Audited
가 안 붙어 있으면, - Envers가 User의 감사 데이터를 User_aud 테이블에 저장할 때,
- User에는 존재하지도 않는 NDA 필드가 살짝 이상한 형태로 묻어들어가서 위와 같은 에러가 난다.
그래서 명시적으로 저장되는 User를 기준으로 일대일 단방향(User -> NDA)으로 연관 관계를 수정하고, NDA에도 @Audited
를 붙여주고 _aud
테이블 생성해서 해결..
이거 envers의 버그일 수도 있겠다 싶은 생각도 든다.
여튼 경험 상 Envers의 오류가 나면 원인 찾는데 정말 많은 비용이 드는 것 같다.
최대의 단점은 감사 기능임에도 불구하고 Envers 쪽에서 에러가 나면 감사 기능만 안 되는 게 아니라 비즈니스 전체가 안 돈다는 점이다.
테스트 관점에서도 Envers의 감사 기능은 개발자가 작성한 서비스 메서드 코드의 return 문 이후에 동작하므로,
서비스 + Repository 구간만 통합 테스트를 하면 위와 같은 오류를 사전에 감지할 수 없다. 감지한다고 해도 원인 찾기 어렵기는 마찬가지고..