JPA 스터디 - 3

한상우·2022년 11월 26일
0

JPA

목록 보기
3/7

5장 목표


  • 객체의 참조와 테이블의 외래 키를 매핑

단방향 연관관계


  • 객체 연관관계와 테이블 연관관계의 차이

    • 객체는 참조로 연관관계를 맺음 (단방향만 가능)
    • 테이블은 외래 키로 연관관계를 맺음 (양방향이 가능)
      • 객체를 양방향으로 참조하려면 단방향 연관관계 2개를 만들어야 함
  • 객체 그래프 탐색: 객체가 참조를 통해서 연관관계를 탐색

  • 조인: DB가 외래키를 사용해 연관관계를 탐색

JPA 사용

@Entity
public class Member {
    @Id
    private String id;

    @ManyToOne
    @JoinColumn(name="TEAM_ID")
    private Team team;

}
  • @ManyToOne : 다대일(N:1) 관계

  • @JoinColumn : 외래키를 매핑할 때 사용

  • 저장

  • 조회

  • 수정

  • 연관관계 제거 member1.setTeam(null);

양방향 연관관계


  • DB 테이블은 외래키 하나로 양방향 조회 가능
@Entity
public class Team {

    @Id
    private String id;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<Member>();
}
  • OneToMany : 일대다 (1:N) 관계

  • mappedBy 속성이 뭐지?

    • 테이블은 외래키 하나로 두 테이블의 연관관계를 관리하지만, 객체는
      양방향 연관관계로 설정하기 위해 참조가 2개 필요하다. 따라서 둘 사이에
      차이가 발생,
    • JPA 에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를
      관리해야 함, 이를 연관관계 주인이라고 한다.
    • 연관관계의 주인만이 DB 연관관계와 매핑되고, 외래 키를 관리할 수 있다
    • 주인은 mappedBy 속성을 사용하지 않는다.
    • 연관관계의 주인은 외래 키가 있는 곳으로 해라
      member와 team은 다대일 관계이므로
      외래키의 주인은 member 다. 때문에 mappedBy는 team에 있어야 함
  • 저장

  • 연관관계의 주인이 외래 키를 관리하기에, 주인이 아닌 방향은 값을 설정하지 않아도 외래키 값이 정상 입력된다.

  • 하지만, 순수한 객체까지 고려한다면 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다.

6장

다양한 연관관계와 매핑


연관관계를 매핑할 때 고려해야할 점

  • 다중성
  • 단방향, 양방향
  • 연관관계의 주인

다중성

  • 다대일
  • 일대다
  • 일대일
  • 다대다
    • 실무에서는 거의 안쓴다고 한다. (진짜??)
    • 다대다 관계일 때는 중간에 연결 테이블을 놔줘서 일대다 다대일 관계로 만들어줘야 하는데 연결 테이블이 단순히 연결만 하고 끝나지 않음. 연결 테이블은 매핑정보만 넣는 것이 가능한데, 연결테이블에 추가 데이터가 많이 들어갈 수 있다. (@ManyToMany

단방향, 양방향

  • 테이블에서는 외래키 사용하여 양방향 쿼리 가능
  • 객체는 참조용 필드를 가지고 있는 객체만 참조된 객체 조회 가능

연관관계 주인

  • JPA는 두 객체 연관관계 중 하나를 정해서 DB 외래키를 관리
  • 연관관계의 주인이 아니면 mappedBy 속성 사용

모든 연관관계 확인


다대일


단방향

@Entity
public class Member {
	
	@ManyToOne
	@JoinColumn(name = "TEAM_ID")
	private Team team
}
  • Member 의 team 필드를 team_id 외래키와 매핑

양방향

  • 실선: 연관관계의 주인
  • 점선: 연관관계의 주인이 아님
  • JPA는 외래키를 관리할 때 연관관계의 주인만 사용한다. (다대일 관계에서는 다에 외래키가 있음) 주인이 아닌 Team.members 는 단순히 조회를 위해 사용
  • 양방향 관계는 항상 서로 참조해야 함

일대다


단방향

  • 이 매핑은 반대쪽 테이블에 있는 외래키를 관리함
  • 이 매핑에서는 @JoinColumn 을 명시해줘야 함, 안하면 - 연결테이블을 중간에 두고 연관관계를 관리함 (지금은 바로 team_id로 매핑 해줬지만, 안해주면 join 테이블 전략을 사용한다 (7장))
@Entity
public class Team {
	@OneToMany
	@JoinColumn(name = "team_id") // member table의 team_id
	private List<Member> members = new ArrayList<Member>();
}
  • 매핑한 객체가 관리하는 외래키가 다른 테이블에 있는 단점.
    • 연관관계 처리를 위한 UPDATE SQL을 추가 진행해야 함.

      INSERT member1
      INSERT member2
      INSERT team1 -> UPDATE member1.fk UPDATE member2.fk

양방향

  • 일대다 양방향 매핑은 존재하지 않는다.
  • DB 특성상 (다대일, 일대다) 항상 다 쪽에 외래키가 존재, @OneToMany 는 연관관계 주인이 될 수 없음

일대일


  • 주 테이블, 대상 테이블 누가 외래키를 가질지 선택

주 테이블에 외래키

단방향

@Entity
public class Member {
	
	@OneToOne
	@JoinColumn(name = "team_id")
  private Team team;
}

양방향

@Entity
public class Team {
	@OneToOne(mappedBy = "team")
	private Member member;
}
  • Member 가 외래키를 가지고 있으니까 member.team이 연관관계 주인

대상 테이블(테이블 상 외래키가 없는쪽)에 외래키

단방향

  • JPA 가 허용하지 않음 (왜 일대다는 되는데 ??)

양방향

  • Member 가 연관관계 주인이였지만, 대상 테이블에 외래키를 두고 싶다면, 대상 엔티티인 Team을 연관관계 주인으로 만들어

다대다


  • 테이블은 다대다 관계를 테이블 2개로 표현할 수 없고, 중간에 연결 테이블을 추가해야 한다.
  • 객체는 2개로 다대다 관계를 만들 수 있다

단방향

@Entity
public class Member {
	@Id @Column(name="member_id")
	private String id;

	@ManyToMany
	@JoinTable(name = "member_product",
						 joinColumns = @JoinColumn(name = "member_id"),
						 inverseJoinColumns = @JoinColumn(name = "product_id"))
  private List<Product> products = new ArrayList<Product>();

}

@Entity
public class Product {
	@Id @Column(name = "product_id")
	private String id;
}
  • @ManyToMany @JoinTable 을 이용해 연결 테이블 매핑
  • 회원_상품 엔티티 없이 매핑 할 수 있음
  • 회원_상품 테이블은 다대다를 풀어내기 위한 연결 테이블일 뿐.

양방향

@Entity
public class Product {
	@Id @Column(name = "product_id")
	private String id;

	@ManyToMany(mappedBy = "products")
	private List<Member> members;
}

다대다 매핑은 실무에서 사용하지 말자

  • 연결 테이블이 다순히 연결만 하고 끝나지 않음. 보통은 추가적인 컬럼이 더 필요함 만약 추가적인 컬럼을 넣고 연결 테이블을 사용하려면 위 예시처럼 멤버와 상품 엔티티에 일대다, 다대일 관계를 넣어주고 MemberProduct 를 만들어줌
    @Entity
    @IdClass(MemberProductId.class)
    public class MemberProduct {
    	
    	@Id
    	@ManyToOne
    	@JoinColumn(name = "member_id")
    	private Member member;
    
    	@Id
    	@ManyToOne
    	@JoinColumn(name = "product_id")
    	private Product product;
    }
    
    public class MemberProductId implements Serializable {
    	...
    }
    회원_상품 엔티티는 member_idproduct_id 로 이루어진 복합키를 지닌다. JPA에서는 복합키를 사용하기 위한 규칙이 있다
    1. 복합 키는 별도의 식별자 클래스로 만들어야 한다
    2. Serializable 를 구현해야 함 - equals와 hashCode 메소드를 구현해야 함
    3. 기본 생성자가 있어야 함
    4. 식별자 클래스는 public

식별관계

  • 부모의 기본키를 받아서 자신의 기본키 + 외래키로 사용

비식별 관계

  • 부모의 기본키를 외래키로만 사용, 새로운 키 추가

대리키를 사용함으로써 간단하게 다대다를 구현할 수 있다

  • 단순히 새로운 아이디를 만들고. member_id나 product_id 를 매핑

싹다 양방향으로 하는건 문제있다

  • 쓸데 없는 필드가 추가
  • 순환참조 문제 발생할 수 있음
profile
안녕하세요 ^^

0개의 댓글