Skip to content

Commit

Permalink
[dev] 상품 조회 성능 개선 - 캐시 AOP 적용
Browse files Browse the repository at this point in the history
issue: 140
  • Loading branch information
pak0426 committed Oct 15, 2024
1 parent 9690c0e commit 2de850e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.mini.joymall.commons.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
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;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@EnableCaching
@Configuration
public class RedisCacheConfig {

@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
PolymorphicTypeValidator typeValidator = BasicPolymorphicTypeValidator
.builder()
.allowIfSubType(Object.class)
.build();

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.activateDefaultTyping(typeValidator, ObjectMapper.DefaultTyping.NON_FINAL);
GenericJackson2JsonRedisSerializer redisSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);

RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(120))
.computePrefixWith(CacheKeyPrefix.simple())
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));

return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(cacheConfiguration)
.build();
}
}
32 changes: 3 additions & 29 deletions src/main/java/com/mini/joymall/product/service/ProductService.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,27 @@
package com.mini.joymall.product.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mini.joymall.product.domain.entity.Product;
import com.mini.joymall.product.domain.repository.ProductRepository;
import com.mini.joymall.product.dto.ProductDTO;
import com.mini.joymall.product.dto.response.ProductPageResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.NoSuchElementException;

@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository productRepository;
private final RedisTemplate<String, String> redisTemplate;
private final ObjectMapper objectMapper;

@Cacheable(value = "products", key = "#keyword + '::' + #pageable.pageNumber + '::' + #pageable.pageSize")
public ProductPageResponse search(String keyword, Pageable pageable) {
String cacheKey = "searchProducts::" + keyword + "::" + pageable.getPageNumber() + "::" + pageable.getPageSize();
String cachedData = redisTemplate.opsForValue().get(cacheKey);
if (cachedData != null) {
try {
System.out.println("redis에 캐시된 정보를 가져온다.");
System.out.println(cachedData);
return objectMapper.readValue(cachedData, ProductPageResponse.class);
} catch (Exception e) {
System.err.println("캐시된 데이터 역직렬화 중 오류 발생: " + e.getMessage());
}
}

List<ProductDTO> productDTOS = productRepository.findProductsByNameStartsWith(keyword, pageable.getPageSize(), pageable.getOffset());
long total = productRepository.countProductsByNameRange(keyword);
Page<ProductDTO> productPages = new PageImpl<>(productDTOS, pageable, total);
ProductPageResponse response = ProductPageResponse.from(productPages);

try {
String jsonResponse = objectMapper.writeValueAsString(response);
redisTemplate.opsForValue().set(cacheKey, jsonResponse);
System.out.println("검색 결과를 Redis에 캐시한다.");
} catch (Exception e) {
System.err.println("겸색 결과 캐싱 중 오류 발생" + e.getMessage());
}
return response;
return ProductPageResponse.from(productPages);
}
}
3 changes: 3 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ logging:
springframework:
jdbc:
core: debug
cache: TRACE
data:
redis: DEBUG

---

Expand Down

0 comments on commit 2de850e

Please sign in to comment.