-
4. 연관관계 매핑 기초Spring-Boot/자바 ORM 표준 JPA 프로그래밍 - 기본편 2022. 12. 20. 17:12
- 목표
ㆍ객체와 테이블 연관관계의 차이를 이해
ㆍ객체의 참조와 테이블의 외래 키를 매핑
ㆍ용어 이해
º 방향(Direction) : 단방향, 양방향
º 다중성(Multiplicity) : 다대일(N:1). 일대다(1:N), 일대일(1:1), 다대다(N:M) 이해
º 연관관계의 주인(Owner) : 객체 양방향 연관관계는 관리주인이 필요
1. 단방향 연관관계
- 객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없다.
ㆍ테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
ㆍ객체는 참조를 사용해서 연관된 객체를 찾는다
ㆍ테이블과 객체 사이에는 이런 큰 간격이 있다.
@ManyToOne @JoinColumn(name="TEAM_ID") private Team team;
public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); try { // 저장 Team team = new Team(); team.setName("TeamA"); em.persist(team); Member2 member = new Member2(); member.setUsername("member1"); // member.setTeamId(team.getId()); member.setTeam(team); em.persist(member); em.flush(); em.clear(); // sql문을 보고 싶을때 : 영속성 컨텍스트 캐시데이터 제거 Member2 findMember = em.find(Member2.class, member.getId()); // Long findTeamId = findMember.getTeamId(); // Team findTeam = em.find(Team.class, findTeamId); Team findTeam = findMember.getTeam(); System.out.println("findTeam = " + findTeam.getName()); // team update Team newTeam = em.find(Team.class, 100L); findMember.setTeam(newTeam); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { em.close(); } // 웹어플리케이션이면 WAS가 내려갈때 엔티티매니저팩토리를 닫아줘야한다. emf.close(); } }
2. 양방향 연관관계와 연관관계의 주인
@OneToMany(mappedBy = "team") // Member2의 team 변수명과 연결되어 있다. private List<Member2> member2s = new ArrayList<>();
Member2 findMember = em.find(Member2.class, member.getId()); List<Member2> member2s = findMember.getTeam().getMember2s(); // 역방향조회 for (Member2 m : member2s) { System.out.println("m.getUsername() = " + m.getUsername()); }
- 연관관계의 주인과 mappedBy
ㆍmappedBy = JPA의 멘탈붕괴 난이도
ㆍmappedBy는 처음에는 이해하기 어렵다
ㆍ객체와 테이블간에 연관관계를 맺는 차이를 이해해야 한다.
- 객체와 테이블이 관계를 맺는 차이
ㆍ객체 연관관계 = 2개
º 회원 → 팀 연관관계 1개(단방향)
º 팀 → 회원 연관관계 1개(단방향)
ㆍ테이블 연관관계 = 1개
º 회원 ↔ 팀의 연관관계 1개(양방향)
- 객체의 양방향 관계
ㆍ객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개다.
ㆍ객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 한다.
º A → B(a.getB())
º B → A(b.getA())
- 테이블의 양방향 연관관계
ㆍ테이블은 외래 키 하나로 두 테이블의 연관관계를 관리ㆍMEMBER.TEAM_ID 외래 키 하나로 양방향 연관관계 가짐 ( 양쪽으로 조인할 수 있다 )
SELECT * FROM MEMBER M JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID SELECT * FROM TEAM T JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
* 객체에서는 단방향 관계가 2개일 때 둘 중 하나로 외래 키를 관리해야 한다.
- 연관관계의 주인(Owner)
양방향 매핑 규칙
ㆍ객체의 두 관계중 하나를 연관관계의 주인으로 지정
ㆍ연관관계의 주인만이 외래 키를 관리(등록, 수정)
ㆍ주인이 아닌쪽은 읽기만 가능
ㆍ주인은 mappedBy 속성 사용X
ㆍ주인이 아니면 mappedBy 속성으로 주인 지정
- 누구를 주인으로?
ㆍ외래 키가 있는 곳을 주인으로 정해라 - N:1 관계에서 외래키가 있는곳이 N이 된다.
ㆍ여기서는 Member.team이 연관관계의 주인
3. 양방향 연관관계와 연관관계의 주인2 - 주의점, 정리
- 양방향 매핑시 가장 많이 하는 실수 (연관관계의 주인에 값을 입력하지 않음)
// 저장 Team team = new Team(); team.setName("TeamA"); em.persist(team); Member2 member = new Member2(); member.setUsername("member1"); // 역방향(주인이 아닌 방향)만 연관관계 설정 team.getMember2s().add(member); // mappedBy는 읽기 전용 // jpa에서 insert, update 할때 사용 X em.persist(member);
- 양방향 매핑시 연관관계의 주인에 값을 입력해야 한다. ( 순수한 객체 관계를 고려하면 항상 양쪽다 값을 입력해야 한다 )
Team team = new Team(); team.setName("TeamA"); em.persist(team); Member2 member = new Member2(); member.setUsername("member1"); team.getMember2s().add(member); // 연관관계의 주인에 값 설정 member.setTeam(team); //** em.persist(member);
ㆍ양쪽 다 값을 입력안하고, flush, clear를 안해준다면 1차 캐시에서 값을 못찾을 수가 있기에 양쪽다 값을 입력한다
- 양방향 연관관계 주의 - 실습
ㆍ순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자
ㆍ연관관계 편의 메소드를 생성하자
º getter, setter는 로직이 없을때, 로직이 있다면 이름을 만들어줄 것!
public void changeTeam(Team team) { this.team = team; team.getMember2s().add(this); }
ㆍ양방향 매핑시에 무한 루프를 조심하자
º 예: toString(), lombok, JSON 생성라이브러리
º toString으로 서로서로를 호출 - lombok에서 toString 만드는 것은 쓰지마라! : StackOverflowError
º controller에서 Entity를 절대 반환하지마라 - 무한루프, Entity 변경 문제
- 양방향 매핑 정리
ㆍ단방향 매핑만으로도 이미 연관관계 매핑은 완료
º 처음에는 단방향 매핑으로 설계할 것
ㆍ양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐
ㆍJPQL에서 역방향으로 탐색할 일이 많음
ㆍ단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨 ( 테이블에 영향을 주지 않음 )
- 연관관계의 주인을 정하는 기준
ㆍ비즈니스 로직을 기준으로 연관관계의 주인을 선택하면 안됨
ㆍ연관관계의 주인은 외래 키의 위치를 기준으로 정해야함
'Spring-Boot > 자바 ORM 표준 JPA 프로그래밍 - 기본편' 카테고리의 다른 글
6. 고급 매핑 (0) 2022.12.21 5. 다양한 연관관계 매핑 (0) 2022.12.21 3. 엔티티 매핑 (0) 2022.11.16 2. 영속성 관리 - 내부 동작 방식 (0) 2022.11.16 1. JPA 소개 & JPA 시작하기 (0) 2022.11.14