연관관계 세팅을 한 쪽에만 하는 경우이다. -> Member에만 Team에 대한 정보가 존재
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
// @Column(name = "TEAM_ID") // JPA를 사용하지 않고, 테이블 중심으로 설계한 경우
// private Long teamId;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
…
}
@ManyToOne
, @ManyToMany
, @OneToMany
, @OneToOne
을 연관관계에 맞게 사용한다.
@JoinColumn
을 이용해 FK 컬럼의 이름을 지정한다.
JPA가 연관관계를 지정한 엔티티의 id값을 이용하여 자동으로 저장하고 조회시에도 해당 값을 이용한다.
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
…
양방향인 경우 Team 엔티티에도 Member에 대한 정보가 존재한다.
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
…
}
mappedBy = "team"
: Member
엔티티에 있는 team
과 연결된다는 의미이다.
FK값이 있는 쪽이 연관관계의 주인이 되며, 연관관계의 주인이 있는 쪽이 업데이트 돼야 최종적으로 데이터가 변경된다.
Collection
의 경우 초기에 필드에서 초기화 하는 것을 권장한다.
메모리상 손해보다 null과 같은 오류를 방지하는 것이 더 가치가 높다.
객체의 양방향 관계는 사실상 서로 다른 단방향 관계 2개이다.
따라서 외래키를 관리할 연관관계의 주인을 지정해줘야 한다.
mappedBy
속성이 없는 쪽이 연관관계의 주인이 된다. 그리고 연관관계의 주인만이 외래키를 관리(등록, 수정) 할 수 있다.
주인이 아닌 쪽은 읽기만 가능하다.
외래키가 존재하는 쪽을 주인으로 정하는 것이 기본이다.
비즈니스 로직상 중요하다고 주인이 아니다.
순수 객체상태일 때를 고려해서 양방향 연관관계를 설정하는 경우, 연관관계 메소드를 생성해주는 것이 좋다.
but 무한 루프를 조심해야 한다.
연관관계 매핑시 고려사항 3가지
• 다중성 : 다대일, 일대다, 일대일, 다대다
• 단방향, 양방향 : 객체는 참조 필드가 있는 쪽에서만 다른 객체에 접근할 수 있다.
• 연관관계의 주인 : 외래키를 관리하는 참조
@ManyToOne
public class Member{
private Long id;
private String name;
@ManyToOne
private Team team;
}
@OneToMany
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자
public class Team{
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "member_id")
private List<Member> members = new ArrayList<>();
}
@JoinColumn
을 꼭 사용해야 한다. 그렇지 않으면 조인테이블 방식을 사용하게 된다.
@OneToOne
@ManyToMany
@JoinTable
을 이용해 연결 테이블을 지정해준다.하지만 연결테이블은 단순히 연결만 하고 끝나지 않는다. 추가 데이터가 들어갈 수 있으므로, 직접 연결 테이블 엔티티를 만들어서 관리하는 것이 옳다.
@JoinColumn
속성
- name
: 매핑할 외래키 이름
default : 필드명 + _ + 참조하는 테
이블의 기본 키 컬럼명
- referencedColumnName
: 외래키가 참조하는 대상 테이블 컬럼명
default : 참조 테이블 기본키 컬럼명
- foreignKey
: 외래 키 제약조건을 직접 지정한다.( 테이블 생성시에)
- uniquenullable, insertable, updatable, columnDefinition, table : @Column
속성과 동일
@ManyToOne
속성
- optional
: false 설정시 연관된 엔티티가 항상 존재해야 한다.
default : TRUE
@OneToMany
속성
- mappedBy
: 연관관계 주인 필드를 선택한다.
@ManyToOne
, @OneToMany
공통 속성
- fetch
: 패치 전략 설정 EAGER, LAZY
@ManyToOne, @OneToOne 의 경우 default가 EAGER이므로 LAZY로 지정해줘야한다.
EAGER로 설정하면 로직이 복잡해졌을 때 예상치 못한 부분에서 쿼리가 날아가게 된다.
- cascade
: 영속성 전이, 생명주기가 같은 경우 지정한다.
관계형 데이터베이스와 객체지향 언어의 차이 중 상속관계의 존재 유무가 있었다.
이를 해결하기 위한 방안 슈퍼타입 서브타입 모델을 구현하는 것이고, 총 3개의 전략이 있다.
-> 조인 전략, 단일 테이블 전략, 구혙클래스마다 테이블 전략
@Inheritance(strategy = InheritanceType.XXX)
@DiscriminatorColumn(name="DTYPE")
: 자식 타입마다 구분할 수 있는 값을 저장하는 컬럼 이름 지정 default = DTYPE@DiscriminatorValue("XXX")
: DicriminatorColumn 에 저장될 값을 설정, default = 엔티티 이름가장 기본적으로 생각할 수 있는 방법으로, FK를 이용해 슈퍼타입과 서브타입의 관계를 구현하는 방식이다.
장점
- 테이블 정규화
- 외래 키 참조 무결성 제약조건 활용 가능
- 저장공간 효율화
단점
- 조회시 조인을 많이 사용 -> 성능 저하
- 조회 쿼리가 복잡하다
- 데이터 저장시 INSERT 를 2번 실행한다. (슈퍼, 서브 각각 1번)
한 테이블(슈퍼타입)에 모든 자식 엔티티의 속성을 포함시켜 하나의 테이블로 상속관계에 대한 정보를 구현하는 방식이다.
장점
- 조인이 필요없으니까 조회 쿼리가 단순하고 성능이 빠르다.
단점
- 자식 엔티티가 매핑한 컬럼은 모두 null값이 허용된다.
- 한 테이블에 모든 정보를 저장하므로 저장공간이 비효율적이고, 조회 성능이 오히려 느려질 수 있다.
자식테이블에 부모엔티티 정보를 각각 모두 담는 구현방식이다.
이 전략은 추천하지 않는다.
장점
- null값 허용 x
- 서브 타입을 명확히 구분해서 처리할 때 효과적이다.
단점
- 자식 테이블을 통합해서 처리하기 어렵다.
공통 속성을 처리할 때 사용한다.
부모 클래스는 자식 클래스에 매핑 정보만 제공하고 독자적으로는 사용이 불가능하다. 상속관계와 다른다.
직접 생성해서 사용하지 않기 때문에 추상 클래스를 권장한다.
주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용한다.
@Entity 클래스는 엔티티나 @MappedSuperclass로 지
정한 클래스만 상속 가능하다.