@OneToOne
@JoinColumn과
@OneToOne
를 통해 할 수 있다.
@Entity(name = "Team")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "team_id")
private Long id;
private String teamName;
}
@Entity(name = "Member")
@Getter
@NoArgsConstructor
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long id;
private String name;
@OneToOne
@JoinColumn(name = "team_id")
private Team team;
}
@JoinColumn
을 통해 관계를 맺고 반대쪽은 mappedBy
속성을 사용하여 관계를 맺으면 된다. @OneToOne(mappedBy = "team")
private Member member;
어떤 A와 B가 연관관계가 있을 때 A를 호출할 때 항상 B도 함께 호출되면 효율적이지 못하다. 이럴 때 프록시를 활용하여 문제를 해결할 수 있다.
1) Client가 getName()을 호출한다.
2) 호출받은 프록시가영속성 콘텍스트에 초기화를 요청한다.
3) 영속성 콘텍스트에 이미 값이 있다면 바로 4번으로 갈 테지만 그렇지 않다면 DB에 조회한다.
4) 조회된 데이터로 실제 엔티티를 생성한다.
5) 생성된 실제 엔티티를 프록시가 조회하여 반환해준다.
System.out.println("=================== 호출 전 ===================");
System.out.println("findMember.getClass() = "+findMember.getClass());
System.out.println("findMember.getName() 첫번째 호출 = "+findMember.getName());
System.out.println("findMember.getName() 두번째 호출 = "+findMember.getName());
System.out.println("=================== 호출 후 ===================");
===================호출 전===================
findMember.getClass()=
class blogJpa.Member$HibernateProxy$PnhnxVd7
Hibernate:
select
생략...
from
Member member0_
left outer join
Team team1_
on member0_.team_id=team1_.team_id
where
member0_.member_id=?
findMember.getName()첫번째 호출=Dexter
findMember.getName()두번째 호출=Dexter
===================호출 후===================
즉시 로딩이란 객체 A를 조회할 때 A와 연관된 객체들을 한 번에 가져오는 것이다.
지연 로딩이란 객체 A를 조회할 때는 A만 가져오고 연관된 애들은 프록시 초기화 방법으로 가져온다.
@ManyToOne
, @OneToOne
: 기본값이 즉시 로딩
@OneToMany
, @ManyToMany
: 기본값이 지연 로딩
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id")
private Team team;
Team team1=new Team();
team1.setTeamName("team1");
em.persist(team1);
Team team2=new Team();
team2.setTeamName("team2");
em.persist(team2);
Member m1=new Member();
m1.setName("Dexter");
m1.setTeam(team1);
em.persist(m1);
Member m2=new Member();
m2.setName("James");
m2.setTeam(team2);
em.persist(m2);
em.flush();
em.clear();
List<Member> members = em.createQuery("select m from Member m", Member.class)
.getResultList();
[성현님의 블로그를 참고해 주세요 - https://goshk95.tistory.com/218]
우리는 앞에서 @OneToOne 은 기본값이 즉시 로딩이고 즉시 로딩의 N+1 등의 문제들을 페치조인으로 회피하기 위해 지연로딩을 권장한다고 하였다. 그렇다면 이질문을 한 이유가 무엇일까?
결론적으로 말하면 OneToOne 은 양방향 매핑의 경우 지연로딩이 적용되지 않는 문제가 존재한다.
@OneToOne
은 즉시 로딩이다.@OneToOne
관계에서는 지연로딩 적용에 문제가 없다@OneToOne
관계에서는 FetchType을 Lazy로 설정하더라도 Eager로 동작하는 경우가 있다.@OneToOne
양방향 연관 관계에서 연관 관계의 주인이 아닌 쪽 엔티티를 조회할 때, Lazy로 동작할 수 없다.
@Entity(name = "Member")
@Getter
@Setter
@NoArgsConstructor
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long id;
private String name;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
public void setTeam(Team team) {
team.setMember(this);
this.team = team;
}
}
@Entity(name = "Team")
@Getter
@Setter
@NoArgsConstructor
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "team_id")
private Long id;
private String teamName;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "team")
private Member member;
public void setMember(Member member) {
this.member = member;
}
}
@OneToOne
에서 null 은 연관 관계 해당 엔티티가 없는 것을 의미하고, 프록시 객체는 연관관계 해당 엔티티가 존재한다 볼 수 있다.optional=true
상황) 프록시 객체로 감쌀 수 없기 때문이다. optional: 데이터가 필수적(not null)인지, 아닌지(null) 여부 ( default: true )
DB 관점에서 연관관계 주인인 엔티티에 매핑된 테이블에는 연결된 엔티티의 존재를 알 수 있는 컬럼이 존재한다.
null 이 있으면 연관 엔티티가 없는것 이고, null 이 아니면 프록시 객체 설정이 가능하여 LAZY 처리가 가능한다.
@OneToOne
양방향 연관 관계에서 연관 관계의 주인이 아닌 쪽 엔티티를 조회할 때, Lazy로 동작할 수 없다.optional=false
설정을 통해 무조건 Lazy Loading 을 시킨다. 이를 통해 반드시 연관 시 값이 존재함이 보장되어야 한다.PrimaryKeyJoin
의 경우에는 optional=false
일 경우에 데이터 저장 순서가 꼬여버린다. 정상적인 optional=false
가 작동하려면 ForeignKey Join
을 해야한다.@ElementCollection
을 통해 컬렉션을 사용하고 unique 조건으로 데이터가 오직 1개만 들어가게 만든다.OneToOne
-> OneToMany
+ ManyToOne
분리 방법(좋은 방법은 아닌거 같다)[참고 사이트]
https://jeong-pro.tistory.com/249
https://kwonnam.pe.kr/wiki/java/jpa/one-to-one