(3) 일대일
일대일 관계는 양쪽이 서로 하나의 관계만 갖는다.
특징
- 일대일 관계는 그 반대도 일대일 관계다.
- 테이블 관계에서 일대다, 다대일은 항상 다(N) 쪽이 외래 키를 가진다.
- 반면 일대일 관계는 주 테이블이나 대상 테이블 둘 중 어느 곳이나 외래 키를 가질 수 있다.
주 테이블에 외래 키
주 객체가 대상 객체를 참조하는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 참조한다.
외래 키를 객체 참조와 비슷하게 사용할 수 있어서 객체지향 개발자들이 선호
장점 : 주 테이블이 외래 키를 가지고 있어서 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.
대상 테이블에 외래 키
전통적인 DB 개발자들은 보통 대상 테이블에 외래 키를 두는 것을 선호
장점 : 테이블 관계에서 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.
6.3.1 주 테이블에 외래 키
객체지향 개발자들이 선호
JPA도 주 테이블에 외래 키가 있으면 좀 더 편리하게 매핑 가능
단방향
MEMBER
가 주 테이블이고, LOCKER
는 대상 테이블이다.
@Entitypublic class Member {@Id @GeneratedValue@Column(name = "MEMBER_ID")private Long id;private String username;@OneToOne@JoinColumn(name = "LOCKED_ID")private Locker locker;...}@Entitypublic class Locker {@Id @GeneratedValue@Column(name = "LOCKED_ID")private Long id;private String name;...}
양방향
양방향이므로 연관관계의 주인을 정해야 한다. MEMBER
테이블이 외래 키를 가지고 있으므로 Member
엔티티에 있는 Member.locker
가 연관관계의 주인이다.
@Entitypublic class Member {@Id @GeneratedValue@Column(name = "MEMBER_ID")private Long id;private String username;@OneToOne@JoinColumn(name = "LOCKED_ID")private Locker locker;...}@Entitypublic class Locker {@Id @GeneratedValue@Column(name = "LOCKED_ID")private Long id;private String name;@OneToOne(mappedBy = "locker")private Member member;...}
6.3.2 대상 테이블에 외래 키
단방향
일대일 관계 중 대상 테이블에 외래 키가 있는 단방향 관계는 JPA에서 지원하지 않는다.
참고 JPA2.0부터 일대다 단방향 관계에서 대상 테이블에 외래 키가 있는 매핑을 허용함. 하지만 일대일 단방향은 이런 매핑 허용하지 않는다.
이때는
- 단방향 관계를
Locker
에서Member
방향으로 수정하거나- 양방향 관계로 만들고
Locker
를 연관관계의 주인으로 설정해야 한다.
양방향
일대일 매핑에서 대상 테이블에 외래 키를 두고 싶으면 이렇게 양방향으로 매핑한다.
주 엔티티인 Member
엔티티 대신에 대상 엔티티인 Locker
를 연관관계의 주인으로 만들어서 LOCKER
테이블의 외래 키를 관리하도록 했다.
@Entitypublic class Member {@Id @GeneratedValue@Column(name = "MEMBER_ID")private Long id;private String username;@OneToOne(mappedBy = "member")private Locker locker;...}@Entitypublic class Locker {@Id @GeneratedValue@Column(name = "LOCKED_ID")private Long id;private String name;@OneToOne@JoinColumn(name = "MEMBER_ID")private Member member;...}
주의 : 프록시 사용 시 외래 키를 직접 관리하지 않는 일대일 관계는 지연 로딩으로 설정해도 즉시 로딩된다.
=>
Member.locker
는 지연 로딩할 수 있지만,Locker.member
는 지연 로딩으로 설정해도 즉시 로딩된다.이것은 프록시의 한계 때문에 발생하는 문제인데, 프록시 대신
bytecode instrumentation
을 사용하면 해결할 수 있다.