정말 어려웠다.. 각각 말을 맞추면서 작성을 했지만, 결국 오류를 일으켰다..
그나마 내 기능은 회원가입 로그인으로, 베이스코드를 빨리 만들어준 시점에서 더이상 병합과정에서 충돌이 일어나지 않았지만, 상점기능, 메뉴기능, 주문관리 기능을 맡은 팀원들은 병합과정에서 충돌을 겪어야 했다.
특히 주문관리를 맡은 팀원분은 정말 많은 고생을 했다.. 코드를 예측해서 작성하는 과정을 거치고, 그만큼 오류가 많은 코드가 완성되었기 때문이다.. 심지어 가장 양이 많고 중요한 부분이라 많은 고생을 하셨다.
오류의 원인은 크게 두가지였고 다음과 같다.
1. @OneToOne 양방향 매핑시 LazyLoding 이슈
정말 가장 중요한 문제였다. 모두가 잘 모르는 문제였고, 덕분에 매핑과, 지연로딩에 대해 확실하게 감을 잡을 수 있었다.
아래와 같은 이유로 @OneToOne 양방향 매핑시 오류가 발생했다.
정확하게는 테이블을 조회할 때, 외래 키를 가지고 있는 테이블(연관 관계의 주인)에서는 외래 키를 가지지 않은 쪽에 대한 지연 로딩은 동작하지만, mappedBy 속성으로 연결된 외래 키를 가지지 않은 쪽에서 테이블을 조회할 경우 외래 키를 가지고 있는 테이블(연관 관계의 주인)에 대해서는 지연 로딩이 동작하지 않고 N+1 쿼리가 발생하게 되는 것입니다.
줄이자면 다음과 같다.
@OneToOne 관계에서는 연관관계 주인이 아닌 곳에서 조회할 때 N + 1 문제가 발생한다.
아직 완전히 이해하지는 못한것 같다.. 질문을 좀 해야겠다. 어째서 무한 반복이 아닌 N+1인가..
2. Transactional 내부에서 연관관계 미리 조회
아래 코드를 보자 @Transactional이 설정되어 있다.
@Transactional
public CartResponseDto addMenu(Long menuId, Long userId) {
User user = findUserById(userId);
Cart cart = findCartByUser(user);
Menu menu = findMenuById(menuId);
AddedMenu addedMenu = findAddedMenuByCartAndMenu(cart, menu);
Store store = menu.getStore();
cart.updateCart(store);
if (addedMenu == null) {
addedMenu = new AddedMenu(menu, cart);
addedMenuRepository.save(addedMenu);
}
else {
addedMenu.updateAddedMenu();
}
return new CartResponseDto(cart);
}
만일 userId가 아닌 바로 User을 받는다면 LazyInitializationException 오류가 발생한다.
이유는 아래 코드에서 나타난다.
@Entity
@Getter
@NoArgsConstructor
@Table(name = "user")
public class User {
...코드들...
@OneToMany(mappedBy = "user", orphanRemoval = true, fetch = FetchType.LAZY)
private List<Delivery> deliveryList = new ArrayList<>();
...코드들...
}
바로 deliveryList에 지연 로딩이 적용되어 있기 때문이다.
Hibernate의 지연 로딩은 트랜잭션 내에서 이루어져야한다.
하지만 User을 그대로 밖에서 받아올 시 지연 로딩이 적용되어 해당 필드에서 오류가 발생하는 것이다.
고로 User을 트랜잭션 내부에서 받아줘야 한다.
이외에도 Dto들에서 @getter을 해주지 않은 코드, 약속한 것과 다른 형식들이 코드 병합을 어렵게 했다.
그래도 결국 해결했고, 프로젝트의 다음 단계 역할 분담까지 마무리한 하루였다.
'프로젝트 > 미니' 카테고리의 다른 글
Eclipse, MS-SQL 연습용 프로젝트 (2) | 2024.10.10 |
---|---|
웹 미니 프로젝트 총평 (1) | 2023.10.03 |
Cache에 Redis 적용시키기 (0) | 2023.09.23 |
효과적인 부분 문자열 검색(Full-Text, 캐시, Redis) (0) | 2023.09.23 |
프론트엔드 개발 (0) | 2023.09.22 |