Home JPA 일대일 연관관계 매핑 시 고려사항
Post
Cancel

JPA 일대일 연관관계 매핑 시 고려사항

해당 글을 JPA를 사용하면서 일대일(1:1) 관계를 매핑하는 방식과 이를 통해 발생할 수 있는 문제점을 파악하고 이에 따른 해결방법을 고민해보기 위한 글입니다.

일대일 관계에 대한 문제를 알아보기 전에 일대다 또는 다대일 관계 매핑의 경우는 일대일과 어떻게 다른지 알아보도록 하겠습니다.

일대다 단방향보단 다대일 단방향, 필요에 따라서는 다대일 양방향을 선택해야 한다.

일대다 단방향이라는 건 일의 입장이 되는 객체가 테이블 관점에서 사용되는 외래키에 대한 관리를 한다는 뜻입니다. 즉 일쪽의 객체를 외래키의 주인으로 임명한다는 것과 동일합니다.

하지만 문제는 모든 테이블 구조 상 외래키는 다의 입장이 되는 테이블이 가지게 되며 이를 무시한 채로 일의 입장이 되는 테이블을 매핑한 객체가 외래키의 주인이 된다면 가지고 있지 않은 외래키에 대한 정보를 관리해야 하는 상황이 됩니다. 이는 테이블 패러다임의 차이로 비정상적인 구조로 설계가 되는 모습으로 추천할 수 없는 방식입니다. 게다가 이와 같은 구조로 구현한 상태에선 불필요한 UPDATE 문이 발생할 수도 있습니다.

1
2
3
4
예시)
  - 다쪽 데이터 1 저장
  - 다쪽 데이터 2 저장
  - 일쪽 데이터 1 저장 + 다쪽 데이터 1 수정(FK값 수정) + 다쪽 데이터 2 수정(FK값 수정)

그렇기 때문에 1:N 구조의 테이블을 객체로 매핑할 때에는 다대일 단방향 또는 양방향으로 구성하는 것이 가장 적합합니다.

그렇다면 일대일 관계에서 연관관계 주인은 어떻게 설정하는 것이 좋은가?

일대일의 경우에도 연관관계의 주인은 양쪽 모두 설정할 수 있습니다. 다만 각 방식에 따라 가져오는 장단점은 다음과 같습니다.

주 테이블이 연관관계 주인인 경우

1
2
3
4
5
6
7
- 장점
  - 객체의 관점에서 하나의 객체를 통해 연관객체에 대한 정보를 알 수 있다.
  - 주 테이블에 매핑되는 객체 저장 시 INSERT 문 한번만 발생한다.
  - 주 테이블 객체에서 지연로딩 사용이 가능하다.

- 단점
  - 테이블 확장시 외래키가 추가되어야 한다.

대상 테이블이 연관관계 주인인 경우

1
2
3
4
5
6
7
- 장점
    - 테이블 확장 시 테이블 및 객체 수정이 발생하지 않는다.

- 단점
    - 주 테이블 객체 저장 시 INSERT 한번, 연관 객체에 대한 UPDATE 한번이 발생한다.
    - 단방향 관계를 맺을 수 없다.
    - 주 테이블 객체가 연관관계 주인이 아니라 지연 로딩이 되지 않는다.

결국 테이블 관점에서 유연성을 확보할 수 있는 건 대상 테이블을 주인으로 설정하는 것이지만 JPA를 사용하는 입장에선 불필요한 쿼리문과 지원하지 못하는 기능들이 발생합니다.

일대일 관계에서 연관관계 주인이 아닌 경우, 지연 로딩이 되지 않는 이유
연관관계 주인일 경우, 외래키 존재 여부를 통해 연관 객체가 Null인지 아닌지 확인할 수 있어 Null이 아니라면 프록시 객체를 우선 주입합니다. 하지만 연관관계 주인이 아닌 경우, 외래키를 가지고 있지 않아 연관 객체가 Null인지 아닌지 알 수 없어 함부로 프록시 객체를 주입할 수 없기 때문에 지연 로딩 자체가 지원할 수 없습니다. 참고로 일대다에서는 Collection이 사용되기 때문에 지연 로딩이 가능한데, 이는 연관 객체가 Null이라면 빈 Collection을 리턴해주면 되기에 가능한 것입니다.

그렇다면 일대일 관계를 맺어야 할 때, 어떤 쪽에 외래키를 가지는 것이 좋을까?

해당 내용은 개인적인 의견일 뿐인 점 참고해주시기 바랍니다.

가장 먼저 고려할 점은 일대일 어느 객체에서 다 로 변경될 가능성이 있다면 해당 객체에 외래키를 주는 것이 합리적으로 보입니다. 보통 테이블은 한번 설계되면 변경되기 쉽지 않기에 추후의 확장성을 우선적으로 고려하는 것이 맞다고 봅니다.

다만 위와 같은 판단으로 인해 불필요한 쿼리가 발생하고 이것이 과도한 오버헤드 발생 지점으로 예상되거나 필수적으로 지연로딩을 사용해야 하는 경우라면 외래키의 주인을 바꾸는 것 또한 고민해볼 수 있다고 보입니다. 이때 해당 테이블이 정말로 일대일로 관계를 가지고 있어도 될 지 면밀한 판단히 필요할 것으로 예상됩니다.

즉, 정답은 없지만 위 두 방식으로 인해 발생할 수 있는 문제점과 차이를 명확히 이해하고 이에 따른 알맞은 판단을 내리는 것이 중요하다고 생각합니다.

일대일 관계에서 지연 로딩이 안되는 문제를 해결하는 방법은?

해당 내용은 개인적인 의견일 뿐인 점 참고해주시기 바랍니다.

일대일 관계에서 지연로딩보단 fetch join을 통해 연관 객체까지 함께 데이터를 가져오는 방법도 고려해 볼 수 있습니다. 일대일 관계라면 fetch join으로 인해 발생할 수 있는 쿼리문의 복잡도가 크지 않을 가능성이 높기 때문입니다.

참고자료

This post is licensed under CC BY 4.0 by the author.

트랜잭션&격리수준

JWT 인증 방식이 세션 인증 방식을 대체할 수 있는지에 대한 의문