Close
Close full mode
logo만렙 개발자 키우기

(3) 일대일

Git RepositoryEdit on Github
Last update: a year ago by nowwaterReading time: 2 min

일대일 관계는 양쪽이 서로 하나의 관계만 갖는다.

특징

  • 일대일 관계는 그 반대도 일대일 관계다.
  • 테이블 관계에서 일대다, 다대일은 항상 다(N) 쪽이 외래 키를 가진다.
  • 반면 일대일 관계는 주 테이블이나 대상 테이블 둘 중 어느 곳이나 외래 키를 가질 수 있다.

주 테이블에 외래 키

주 객체가 대상 객체를 참조하는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 참조한다.

외래 키를 객체 참조와 비슷하게 사용할 수 있어서 객체지향 개발자들이 선호

장점 : 주 테이블이 외래 키를 가지고 있어서 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.

대상 테이블에 외래 키

전통적인 DB 개발자들은 보통 대상 테이블에 외래 키를 두는 것을 선호

장점 : 테이블 관계에서 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.

6.3.1 주 테이블에 외래 키

객체지향 개발자들이 선호

JPA도 주 테이블에 외래 키가 있으면 좀 더 편리하게 매핑 가능

단방향

MEMBER가 주 테이블이고, LOCKER는 대상 테이블이다.

image

@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKED_ID")
private Locker locker;
...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKED_ID")
private Long id;
private String name;
...
}

양방향

양방향이므로 연관관계의 주인을 정해야 한다. MEMBER 테이블이 외래 키를 가지고 있으므로 Member 엔티티에 있는 Member.locker가 연관관계의 주인이다.

image

@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKED_ID")
private Locker locker;
...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKED_ID")
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
...
}

6.3.2 대상 테이블에 외래 키

단방향

image

일대일 관계 중 대상 테이블에 외래 키가 있는 단방향 관계는 JPA에서 지원하지 않는다.

참고 JPA2.0부터 일대다 단방향 관계에서 대상 테이블에 외래 키가 있는 매핑을 허용함. 하지만 일대일 단방향은 이런 매핑 허용하지 않는다.

이때는

  1. 단방향 관계를 Locker에서 Member 방향으로 수정하거나
  2. 양방향 관계로 만들고 Locker를 연관관계의 주인으로 설정해야 한다.

양방향

일대일 매핑에서 대상 테이블에 외래 키를 두고 싶으면 이렇게 양방향으로 매핑한다.

주 엔티티인 Member 엔티티 대신에 대상 엔티티인 Locker를 연관관계의 주인으로 만들어서 LOCKER 테이블의 외래 키를 관리하도록 했다.

image

@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne(mappedBy = "member")
private Locker locker;
...
}
@Entity
public 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을 사용하면 해결할 수 있다.

🚀 JPA — Previous
(2) 일대다
Next — 🚀 JPA
(4) 다대다