Skip to content

Commit

Permalink
카테고리 조회 성능 개선 (#334)
Browse files Browse the repository at this point in the history
  • Loading branch information
kmw2378 authored Jul 29, 2024
2 parents e9695bd + e1c0797 commit 267eec1
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 185 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package org.kakaoshare.backend.common.config;

import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.CacheKeyPrefix;
Expand All @@ -19,11 +23,9 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;

import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;

@Configuration
@EnableCaching
public class RedisConfig {
private static final long DEFAULT_CACHE_DURATION = 1L;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,43 @@
package org.kakaoshare.backend.domain.category.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Builder;
import lombok.Getter;
import org.kakaoshare.backend.domain.category.entity.Category;

import com.querydsl.core.annotations.QueryProjection;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@JsonSerialize
@NoArgsConstructor
public class CategoryDto {
public static final long PARENT_ID = -1L;
private final Long categoryId;
private final String categoryName;
private Long categoryId;
private String categoryName;

@JsonInclude(JsonInclude.Include.NON_NULL)
private final Long parentId;
private Long parentId;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonInclude(Include.NON_EMPTY)
private final List<CategoryDto> subCategories = new ArrayList<>();
private final TabType defaultTab;
private int level;


@Builder
public CategoryDto(Long categoryId, String categoryName, Long parentId) {

private final TabType defaultTab=TabType.BRAND;

@QueryProjection
public CategoryDto(Long categoryId, String categoryName, Long parentId, List<CategoryDto> subCategories) {
this.categoryId = categoryId;
this.categoryName = categoryName;
this.parentId = parentId;
this.defaultTab = TabType.BRAND;//브랜드를 조회하는것이 화면 로딩과정에서 쿼리를 최소화 가능해보임
this.subCategories.addAll(subCategories);
}

public static CategoryDto from(final Category category) {
CategoryDto categoryDto = CategoryDto
.getCategoryDtoBuilder(category)
.build();

giveLevelAndSubCategories(categoryDto, category);

return categoryDto;
}

private static void giveLevelAndSubCategories(CategoryDto dto, Category category) {
dto.level=2;
if (!category.isChildEmpty()) {
dto.level = 1;
dto.getSubCategories().addAll(getChildrenDtos(category));
}
}

private static List<CategoryDto> getChildrenDtos(final Category category) {
return category.getChildren().stream()
.map(CategoryDto::from)
.toList();
@QueryProjection
public CategoryDto(Long categoryId, String categoryName, Long parentId) {
this.categoryId = categoryId;
this.categoryName = categoryName;
this.parentId = parentId;
}

@Override
Expand All @@ -70,16 +52,4 @@ public String toString() {
", defaultTab=" + defaultTab +
'}';
}

private static CategoryDtoBuilder getCategoryDtoBuilder(final Category category) {
Long parentId = Optional
.ofNullable(category.getParent())
.map(Category::getCategoryId)
.orElse(null);

return CategoryDto.builder()
.categoryId(category.getCategoryId())
.categoryName(category.getName())
.parentId(parentId);
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
package org.kakaoshare.backend.domain.category.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

import java.util.List;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CategoryHeaderResponse {
private final Long brandCount;
private final Long productCount;
private final Long totalCount;
private final List<SimpleCategoryDto> simpleCategoryDtos;
@Builder
private CategoryHeaderResponse(final Long brandCount, final Long productCount, Long totalCount, final List<SimpleCategoryDto> simpleCategoryDtos) {
this.brandCount = brandCount;
this.productCount = productCount;
this.totalCount = totalCount;
this.simpleCategoryDtos = simpleCategoryDtos;
}

private Long brandCount;
private Long productCount;
private Long totalCount;
private List<SimpleCategoryDto> simpleCategoryDtos;

public static CategoryHeaderResponse of(final Long brandCount, final Long productCount, final List<SimpleCategoryDto> simpleCategoryDtos){
return CategoryHeaderResponse
.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
package org.kakaoshare.backend.domain.category.dto;

import com.querydsl.core.annotations.QueryProjection;
import lombok.Builder;
import lombok.Getter;
import org.kakaoshare.backend.domain.category.entity.Category;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class SimpleCategoryDto {
private final Long categoryId;
private final String categoryName;
private Long categoryId;
private String categoryName;

@Builder
private SimpleCategoryDto(Long categoryId, String categoryName) {
@QueryProjection
public SimpleCategoryDto(Long categoryId, String categoryName) {
this.categoryId = categoryId;
this.categoryName = categoryName;
}
public static SimpleCategoryDto from(final Category category){

public static SimpleCategoryDto from(final CategoryDto categoryDto) {
return SimpleCategoryDto.builder()
.categoryId(category.getCategoryId())
.categoryName(category.getName())
.categoryId(categoryDto.getCategoryId())
.categoryName(categoryDto.getCategoryName())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,30 +30,33 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Table(
indexes = {@Index(name = "idx_category_parent_id",columnList = "parent_id")}
indexes = {
@Index(name = "idx_category_parent_id", columnList = "parent_id"),
@Index(name = "idx_category_id_parent_id", columnList = "category_id, parent_id")
}
)
public class Category extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id")
private Long categoryId;

@Column(nullable = false)
private String name;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "parent_id", referencedColumnName = "category_id")
private Category parent;

@BatchSize(size = 100)//TODO 2024 02 26 21:15:10 : 추후 부모 카테고리당 자식 카테고리 수에 따라 결정하여 최적화
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Category> children;

public boolean isChildEmpty() {
return children.isEmpty();
}

@Override
public String toString() {
return "Category{" +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package org.kakaoshare.backend.domain.category.repository.query;

import org.kakaoshare.backend.domain.category.entity.Category;

import java.util.List;
import java.util.Optional;
import org.kakaoshare.backend.domain.category.dto.CategoryDto;
import org.kakaoshare.backend.domain.category.dto.SimpleCategoryDto;

public interface CategoryRepositoryCustom {

Optional<CategoryDto> findParentCategoryWithChildren(Long categoryId);

Optional<Category> findParentCategoryWithChildren(Long categoryId);

Optional<Category> findChildCategoryWithParentCheck(final Long categoryId, final Long subcategoryId);
Optional<CategoryDto> findChildCategoryWithParentCheck(final Long categoryId, final Long subcategoryId);


List<Category> findAllParentCategories();
List<CategoryDto> findAllParentCategories();
Long countBrand(Long categoryId);
Long countProduct(Long categoryId);


List<SimpleCategoryDto> findChildrenCategory(Long categoryId);
}
Loading

0 comments on commit 267eec1

Please sign in to comment.