Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- java
- JPQL
- 김영한
- 백준
- 스프링 핵심 기능
- 인프런
- db
- Thymeleaf
- http
- springdatajpa
- 스프링 핵심 원리
- Android
- jpa
- 자바
- pointcut
- Servlet
- transaction
- Exception
- JDBC
- 그리디
- AOP
- 스프링
- kotlin
- Proxy
- Spring Boot
- Greedy
- spring
- 알고리즘
- SpringBoot
- QueryDSL
Archives
- Today
- Total
개발자되기 프로젝트
양방향 연관관계와 연관관계 주인 - 주의점 본문
1. 양방향 매핑 시 가장 빈번한 실수
- 연관관계의 주인에 값을 입력하지 않은 실수
- 주인이 아닌 방향 만 연관관계를 설정하면..?
- 주인이 아닌 곳에서 만 값을 입력하면 SQL 나갔다가 rollback됨 ㅋㅋ
Member member = new Member(); member.setUserName("member1"); em.persist(member); Team team = new Team(); team.setName("TeamA"); //주인이 아닌 쪽에서 연관관계 설정 team.getMemberList().add(member); em.persist(team); //team이 영속상태 되면 id값이 들어감.
- Team은 연관관계 주인이 아니다.
- mappedBy는 읽기 전용이고, JPA에 update나 insert 시 mapppedBy는 무시함.
- 즉, mappedBy가 붙은 Team의 MemberList에 member를 추가해도 update, insert 대상이 아님.
@OneToMany(mappedBy = "team") //일대다 매핑에서 나는 뭐랑 연결되어있지? Member 클래스의 Team 필드명. private List<Member> memberList = new ArrayList<>();
- 그래서 연관관계 주인 쪽에서 값을 입력해 줘야 한다.
Team team = new Team(); team.setName("TeamA"); em.persist(team); //team이 영속상태 되면 id값이 들어감. Member member = new Member(); member.setUserName("member1"); member.setTeam(team); em.persist(member);
- 양쪽으로 넣어도됨..? -->예쓰
- 하지만 주인이 아닌 쪽에서 입력해도 읽기 전용이라 JPA에서 안씀 ㅋㅋㅋ
Team team = new Team(); team.setName("TeamA"); em.persist(team); //team이 영속상태 되면 id값이 들어감. Member member = new Member(); member.setUserName("member1"); member.setTeam(team); em.persist(member); //어차피 읽기 전용이라 JPA에서 안씀. team.getMemberList().add(member); em.flush(); em.clear();
2. 결국 양방향 매핑은 양 쪽 다 값을 넣어줘야 함.
- 객체지향 적으로 생각해 보면 앙쪽에 넣는 것이 맞음.
- 만약 Team에서 memberList값을 입력을 하지 않은 상태에서
team.getMemberList()를 호출해 보자.
Team team = new Team();
team.setName("TeamA");
em.persist(team); //team이 영속상태 되면 id값이 들어감.
Member member = new Member();
member.setUserName("member1");
member.setTeam(team);
em.persist(member);
//어차피 읽기 전용이라 JPA에서 안씀.
//team.getMemberList().add(member);
em.flush();
em.clear();
//member의 소속 팀 찾기....흠..
Member findMember = em.find(Member.class, member.getId());
List<Member> memberList = findMember.getTeam().getMemberList();
System.out.println("==================");
for (Member m : memberList) {
System.out.println("member1 = " + m.getUserName());
}
System.out.println("==================");
tx.commit();
- 값은 호출이 된다.
member1 = member1
- 하지만 log를 보면 select 쿼리가 날라간다.
- FK가 매핑이 완료되었기 때문에, Team과 연관된 Member를 쿼리를 날려서 가져오게 된다.
Hibernate:
select
memberlist0_.TEAM_ID as team_id3_0_0_,
memberlist0_.MEMBER_ID as member_i1_0_0_,
memberlist0_.MEMBER_ID as member_i1_0_1_,
memberlist0_.TEAM_ID as team_id3_0_1_,
memberlist0_.USERNAME as username2_0_1_
from
Member memberlist0_
where
memberlist0_.TEAM_ID=?
- 이렇게 양방향으로 안넣어 주게되면 두 가지 문제가 발생한다.
- 1차 캐시에서 조회
- Test case작성 - 지금 예제처첨 flush, clear하면 문제는 없지만. 안하면 지금과 다르게 동작한다.
- team은 영속상태이기 때문에 findTeam은 1차 캐시에서 가져온다.
- 이 때 1차 캐시에 있는 team은 처음 영속성 컨텍스트에 올라간 상태 그대로이다.
- 즉 team의 memberList에는 member정보가 없다.
try{
Team team = new Team();
team.setName("TeamA");
em.persist(team); //team이 영속상태 되면 id값이 들어감.
Member member = new Member();
member.setUserName("member1");
member.setTeam(team);
em.persist(member);
//1차 캐시에 들어간 상태 그대로임..연관관계 세팅 안됨.
Team findTeam = em.find(Team.class, team.getId());
List<Member> memberList = findTeam.getMemberList();
System.out.println("==================");
for (Member m : memberList) {
System.out.println("member1 = " + m.getUserName());
}
System.out.println("==================");
tx.commit()
}
- member값이 없기 때문에 출력할 값이 없다.
==================
==================
- 다른 문제점은 Test case 작성 시 JPA없이 돌아가도록 짜야하는데,
양쪽으로 안넣어주면 문제 발생. - 정리!!! 양쪽에 다! 세팅하자.
3. 정리
- 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자
- 연관관계 편의 메서드를 생성하자
public void setTeam(Team team) { this.team = team; team.getMemberList().add(this); }
- 양방향 매핑시 무한 루프를 조심하자(순환참조 등)
- toString(), lombok, JSON 생성 라이브러리 사용 시 자주 발생.
- 엔티티를 컨트롤러에 반환하지마 ㅋㅋㅋ - 단방향 매핑만으로도 이미 연관관계 매핑은 완료!!
- 단방향 매핑으로 설계를 끝내!! - 양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색)기능이 추가된 것 뿐!!!!!!
- JPQL에서 역방향으로 탐색할 일이 많음
- 단방향 매핑을 잘~~~하고 양방향은 필요할 때 추가해!
어차피 테이블에 영향 없어!! - 연관관계 주인은 외래키 위치를 기준으로!
4. GitHub : 210810 Entity Relationship2
'인프런 > [인프런] 자바ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
다대일 매핑[N:1] (0) | 2021.08.10 |
---|---|
[예제] 연관관계 추가 (0) | 2021.08.10 |
양방향 연관관계와 연관관계 주인. (0) | 2021.08.10 |
단방향 연관관계 (0) | 2021.08.09 |
예제 : 요구사항 분석과 기본 매핑. (0) | 2021.08.09 |
Comments