카페 프로젝트에서 데이터 구조는 아래 사진과 같다.
기존 user와 cafe 테이블만 독립적으로 있던 상황에서 review, scrap, survey가 추가됐다.
reveiw, scrap, survey 모두 user, cafe와 다대일 단방향 관계가 적용될 수 있다.
이 케이스가 향후 확장 가능성 측면에서 가장 바람직 하다고 볼 수 있다. 예를 들어 scarp과 survey의 경우에는 향후 timestamp 등의 필드가 추가될 수 있다.
다대일 단방향이라면 Scrap Entity는 아래와 같이 정의된다.
@Entity
@Table(name="scrap") // name 생략 가능
public class Scarp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "cafe_id")
private Cafe cafe;
}
String jpql = "select u from user u join .
이 경우 scrap과 survey만 가능하다. review는 외래키 외에 다른 필드가 존재하므로 불가능하다.
아래 케이스들은 기본키가 user_id와 cafe_id 2개 합집합이 된다.
추가로 scrap과 survey에서는
scrap의 경우, 테이블이 DB 상에는 존재하나 java코드의 Entity로는 존재하지 않게 된다.
@Entity
@Table
public class User {
@Id
@Column
private String user_id;
@Column
private String nickName;
@Column
private String email;
@Column
private String age;
@Column(name="profile_image_url")
private String imgUrl;
@Column
private String gender;
@ManyToMany
@JoinTable(name = "scrap",
joinColumns = @JoinColumn(name="user_id"),
iverseJoinColumns = @JoinColumn(name="cafe_id"))
private List<Cafe> cafeList = new ArrayList<Cafe>();
}
###@JoinTable 속성정리###
@JoinTable.name : 연결 테이블을 지정. 예시에서는 scrap이 되는거@JoinTable.joinColumns : 연결 테이블이랑 '정의 entity(user)'랑 매핑할 조인 칼럼을 지정. 예시에서는 scrap 테이블의 user_id가 될 것임.
@JoinTable.inverseColumns : 연결 테이블이랑 '정의 entity 기준 상대(cafe)'와 매필할 조인 칼럼을 지정. 예시에서는 scrap 테이블의 cafe_id가 되는 것임
@Entity
@Table
public class Cafe {
@Id
private String cafe_id;
@ManyToMany(mappedBy = "cafeList") // 주인은 user
private List<User> users;
}
그리고 User Entity에 아래와 같이 연관관계 편의 메소드를 추가해준다.
public void addCafe(Cafe cafe) {
cafeList.add(cafe);
cafe.getUsers().add(this);
}
이제 서로 서로 객체를 알아낼 수 있다.
우선 지연로딩은 쿼리문이 2번 나가고, 즉시로딩은 쿼리문 1번(조인)이 나간다.
프로젝트 상황에서 사실, scrap과 review라면 scrap을 조회하는 순간에 user & review가 모두 같은 시점에 필요하게 된다.
따라서 지연로딩할 필요는 없다.
@ManyToOne에서는 디폴트가 EAGER이므로 놔둔다.
지연로딩 + fetch조인의 경우에도 N+1 발생할 수 있다.
scrap Entity 조회 시 유저id랑 카페id랑 2개로 조회하면 결국 레코드 하나 뿐이다.
그리고 scrap Entity 내부에 컬렉션이 존재하지 않는다.
따라서 즉시로딩해도 N+1 문제는 발생하지 않는다.