@OneToOne@OneToManymappedBy@JoinColumn읽기전용으로 적용하기@OneToMany 단방향 적용시 문제점@ManyToOne@ManyToMany다대다 매핑 설정 시, 중간 테이블 엔티티 생성 없이 설정방법(@JoinTable)null 제약 조건과 JPA 조인 전략
- @OneToOne, @OneToMany 등 적용할 때에는 어느 entity에서 어떤 entity값이 필요한 지를 생각해보면 어떻게 적용할 지를 알 수 있음
- ToString.Exclude를 붙여주어서 StackOverflow error를 방지해야함
@OneToOne
- OneToOne은 한쪽에만 붙여서 한쪽에서만 접근 or 양쪽에 붙인다면 한쪽에 ToString.Exclude & mappedBy 해주어야함
- 양쪽에서 둘다 OneToOne & ToString → StackOverFlow error(ToString 순환참조 문제) 가 발생함 → ToString.Exclude를 한쪽에 붙여주기
- mappedBy x → 둘다 서로 참조하게 되어 query에서 join 문이 각각 2번씩 호출되게 됨(book에서 bookHistory를 참조하고 또 bookHistory에서 book을 참조하고..)
- mappedBy 를 적용하게 되면 table 생성 시에는 그 필드가 빠지게 됨
- mappedBy에 지정하는 값은 반대쪽 relation에서 현재 table을 참조할 때의 변수 이름으로 지정
- optional = false 이면 항상 그 값이 존재하게 되어서 쿼리가 inner join으로 해당 relation을 찾게 됨. outer join이 아니라.
@OneToMany
mappedBy
- 엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래 키를 관리하면 되는데, 엔티티를 양방향으로 매핑하면 회원→ 팀, 팀 →회원 두 곳에서 서로를 참조함 (객체의 참조는 둘인데 외래 키는 하나 → 두 객체 연관관계 중 하나를 정해서 테이블의 외래 키를 관리해야 하는데 이것을 연관관계의 주인이라 함)
- 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있음. 주인이 아닌 쪽은 읽기만 할 수 있다
- 주인은 mappedBy 속성 사용x
- 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해야 함
- 연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정해야 함
- @OneToMany(mappedBy=” “) 에 들어갈 값은 연관관계의 주인인 Order.member 즉 entity에서 foreignKey로 매핑되는 필드이름 (테이블에 생성되는 컬럼이름이 아닌 필드이름임)
- 다대일, 일대다 에서는 항상 다 쪽이 외래 키를 가지게 됨
- mappedBy를 해야할 상황에서 안하게 되면 자동으로 테이블이름을 이상하게 참조하여 쿼리가 날아감
- 자동 참조 테이블이름 : <현재 테이블이름>s_<해당 변수명>
@JoinColumn
- 외래 키를 매핑(데이터베이스의 외래 키를 객체에 매핑)할 때 사용함
- @JoinColumn을 명시해주지 않으면 User와 User history를 연결하는 중간 매핑테이블(@JoinTable)이 생성되게 됨
- 위와 같이 되면 매우 비효율적임. → 일대다 단방향 잘못 사용하면 벌어지는 일
- 아래와 같은 시나리오 일때 2번째에서 아주 이상한 행동을 하게 됨. children입장에서는 parent id를 모르기 때문에,10개에 해당하는 것을 다 지우고 나머지 8개를 insert하는 식으로 쿼리가 발생함
parent
가 10개의 Child를 포함하는children
을 가진다.parent.children
에서 Child의 id가 1, 2인 것 2개만 삭제한다.
@JoinTable 로 적용 시 생기는 문제
- 해당 매핑 테이블을 없애기 위해 @JoinColumn을 명시해주면 반대쪽 테이블에 어떤 column으로 join을 적용할 지를 정의해줌
@JoinColumn(name=”member_id”, referencedColumnName = “id”)
- foreign key이름을 member_id로 하고, 상대방 테이블의 id 필드와 join을 할거다
- referencedColumnName 의 컬럼명은 @Column이 붙어있으면 해당 어노테이션에서 정의한 name이름
- 만약 name을 지정해주지 않으면
정의된 필드 이름_반대쪽테이블의pk필드이름
으로 UserHistory 테이블에 추가로 생성됨 - 참조하는 join 필드의 default값은 반대 테이블의 @Id 가 붙은 필드
- Many쪽 테이블에 One에 해당하는 id는 항상 추가됨
읽기전용으로 적용하기
@OneToMany 단방향 적용시 문제점
@OneToMany 단방향 문제점@ManyToOne
- 일반적인 상황에서는 @OneToMany보다 @ManyToOne이 좀 더 깔끔하게 entity를 구성할 수 있음. 그 이유는 One(User.java) 측에서 Many(UserHistory.java)의 id를 가지려면 id 의 list를 가져야 하지만, Many측에서 One(User.java)의 id는 항상 가지고 있기 때문임
- @ManyToOne(optional=false)
@ManyToMany
- 실무 현업에서는 거의 사용되지 않음
- @OneToMany에서 테이블이 생성됐던 것과 마찬가지로 여기서도 매핑 테이블이 생성됨. 그러나 여기서는 그 테이블을 없애는 것이 불가능함. FK를 어느 쪽에서도 가지기 애매하기 때문
- 예시 ( 기존의 N: N 을 중간에 테이블을 하나 만듦으로써 1:N, N:1로 바꾸게 됨)
- User와 Products의 관계(e-commerce)에서 쓰이게됨
- 그러나 이 또한도 자동으로 생기는 매핑 테이블을 쓰지 않고, Order라는 entity를 새로 만들어서 Order : User (N : 1) , Order : Product(N : 1) 이렇게 사용가능함
- 중간 테이블의 PK를 복합키(양쪽 테이블의 PK의 조합)으로 가져갈 수도 있고(식별 관계), 양쪽 테이블의 PK는 FK로만 쓰고 새로운 PK를 정의해서 가져갈 수 있는데(비식별 관계) 후자가 더 간단함
- 식별관계 : 부모 테이블의 기본 키를 받아서 자식 테이블의 기본키 + 외래키로 사용
비식별관계 : 단순히 외래키 로만 사용
다대다 매핑 설정 시, 중간 테이블 엔티티 생성 없이 설정방법(@JoinTable)

- joinColumns : 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정 (JoinTable로 명시된 테이블의 컬럼이름)
- inverseJoinColumns : 반대 방향인 상품과 매핑할 조인 컬럼 정보를 지정 (JoinTable로 명시된 테이블의 컬럼이름)
null 제약 조건과 JPA 조인 전략
- 해당 객체가 null이 가능한지 가능하지 않은 지에 대해 정해주는 파라미터임
- @OneToOne, @ManyToOne(optional=false) 하면 해당 필드는 null이 될 수 없음 → Inner 조인으로 쿼리 실행
- @OneToOne, @ManyToOne(optional=true) 하면 해당 필드는 null이 될 수 있음 → Outer 조인으로 쿼리 실행
- @OneToMany와 @ManyToMany는 어떠한 옵션 값에도 외부조인으로 실행됨