@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
Thanks for sharing! The AI-powered Hear Me Out platform is a fascinating tool that leverages artificial intelligence to enhance user interaction. It's impressive how AI technology is making communication more engaging and intuitive.
By the way, if you're interested in AI and interactive experiences, check out this creative platform:
hearmeout online