store select query (store - owner -menu)
N+1 발생개선방안
기존 store 테이블
@Entity
@Getter
@Table(name = "store")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Store {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/*
*중간 생력
*
*/
@OneToMany(mappedBy = "store", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
private List<Menu> menuList = new ArrayList<>();
@OneToOne
@JoinColumn(name ="owner_id")
private Owner owner;
}
(Menu 는 왜 EAGER 로 해뒀지…? 아 처음 ENTITY 연관관계 설정할때 한번에 다 가져오게 하려고 그런 것 같다….ㅜ 과거의 나 N+1 을 알았다면 그러지 않았을 거야…)
Fetch 타입 Lazy 로 변경
@Entity
@Getter
@Table(name = "store")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Store {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/*
*중간 생력
*
*/
// FetchType 변경
@OneToMany(mappedBy = "store", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<Menu> menuList = new ArrayList<>();
// FetchType 변경
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name ="owner_id")
private Owner owner;
}
변경 후
Hibernate:
/* <criteria> */ select
s1_0.id,
s1_0.address,
s1_0.business_number,
s1_0.description,
s1_0.image_url,
s1_0.name,
s1_0.origin_file_name,
s1_0.owner_id
from
store s1_0
→ 연관관계에 있는 테이블을 더이상 Read 하지 않고 현재 필요한 store 테이블만 select 해 오는 것을 확인 할 수 있었다.

@Service
@RequiredArgsConstructor
public class StoreService {
// 선택한 업장, 해당 업장의 메뉴 목록 반환
public GetStoreDto getStore(Long storeId) {
// 1. store를 한번 검색하고
Store store = storeRepository.getReferenceById(storeId);
// 기존코드 사장님에 있던 메서드와 중복으로 해당 메서드 사용
return getGetMenuList(store);
}
//2. menu 를 조회 하여 한번 더 가져온다
@NotNull
private GetStoreDto getGetMenuList(Store store) {
List<Menu> menus = menuRepository.findByStore(store);
List<GetMenuListDto> menuLists = new ArrayList<>();
for (Menu menu : menus) {
menuLists.add(
new GetMenuListDto(
menu.getId(),
menu.getName(),
menu.getPrice(),
menu.getImageUrl(),
menu.getDescription()
)
);
}
return new GetStoreDto(menuLists, store.getName());
}
}

흠….일단 fetch join을 사용해 보자!