Skip to content

Commit bd05e11

Browse files
committed
refactor: 상품 상세 조회 최적화
- brandId 캐시 사용으로 불필요한 DB 조회 제거 - 실시간 랭킹 조회 연동
1 parent 8626727 commit bd05e11

1 file changed

Lines changed: 12 additions & 13 deletions

File tree

apps/commerce-api/src/main/java/com/loopers/application/product/ProductFacade.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import com.loopers.application.event.product.ProductViewedEvent;
44
import com.loopers.domain.like.service.LikeReadService;
5-
import com.loopers.domain.product.Product;
6-
import com.loopers.domain.product.repository.ProductRepository;
75
import com.loopers.domain.product.service.ProductReadService;
86
import com.loopers.domain.product.command.ProductSearchFilter;
97
import com.loopers.domain.product.enums.ProductSortCondition;
108
import com.loopers.infrastructure.cache.ProductDetailCache;
119
import com.loopers.infrastructure.cache.ProductListCache;
10+
import com.loopers.infrastructure.cache.ProductRankingCache;
1211
import lombok.RequiredArgsConstructor;
1312
import org.springframework.context.ApplicationEventPublisher;
1413
import org.springframework.data.domain.Page;
@@ -29,7 +28,7 @@ public class ProductFacade {
2928
private final LikeReadService likeReadService;
3029
private final ProductDetailCache productDetailCache;
3130
private final ProductListCache productListCache;
32-
private final ProductRepository productRepository;
31+
private final ProductRankingCache productRankingCache;
3332
private final ApplicationEventPublisher eventPublisher;
3433

3534
@Transactional(readOnly = true)
@@ -100,33 +99,33 @@ public ProductDetailInfo getProductDetail(Long productId, Long memberIdOrNull) {
10099
return result;
101100
});
102101

103-
// 2. Product 엔티티 조회 (brandId 획득용)
104-
Product product = productRepository.findById(productId)
105-
.orElseThrow(() -> new com.loopers.support.error.CoreException(
106-
com.loopers.support.error.ErrorType.NOT_FOUND,
107-
"상품을 찾을 수 없습니다."));
108-
109-
// 3. isLikedByMember 동적 계산
102+
// 2. isLikedByMember 동적 계산
110103
boolean isLiked = memberIdOrNull != null && likeReadService.isLikedBy(memberIdOrNull, productId);
111104

112-
// 4. isLikedByMember 필드만 교체해서 반환
105+
// 3. 순위 조회 (실시간)
106+
Integer ranking = productRankingCache.getRank(productId);
107+
108+
// 4. 동적 필드(isLikedByMember, ranking)를 교체해서 반환
113109
ProductDetailInfo result = ProductDetailInfo.builder()
114110
.id(cachedInfo.getId())
115111
.name(cachedInfo.getName())
116112
.description(cachedInfo.getDescription())
113+
.brandId(cachedInfo.getBrandId())
117114
.brandName(cachedInfo.getBrandName())
118115
.brandDescription(cachedInfo.getBrandDescription())
119116
.price(cachedInfo.getPrice())
120117
.stock(cachedInfo.getStock())
121118
.likeCount(cachedInfo.getLikeCount())
122-
.isLikedByMember(isLiked) // ⭐ 동적 계산
119+
.isLikedByMember(isLiked)
120+
.ranking(ranking)
123121
.build();
124122

125123
// 5. ProductViewedEvent 발행 (조회수 집계)
124+
// brandId는 캐시된 정보에서 가져옴 (불필요한 DB 조회 제거)
126125
eventPublisher.publishEvent(new ProductViewedEvent(
127126
memberIdOrNull, // 비로그인 사용자는 null
128127
productId,
129-
product.getBrandId(),
128+
cachedInfo.getBrandId(),
130129
LocalDateTime.now()
131130
));
132131

0 commit comments

Comments
 (0)