- Redis 의존성 추가
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
application.yml에 Redis 설정 추가spring:
datasource:
url: jdbc:mariadb://localhost:3306/sample
username: root
password: password
driver-class-name: org.mariadb.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
redis:
host: localhost
port: 6379
cache:
time-to-live: 60000 # 캐시 TTL (밀리초 단위, 60초)
- Controller
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping("/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
Product product = productService.getProductById(id);
return ResponseEntity.ok(product);
}
@PostMapping
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
Product savedProduct = productService.saveProduct(product);
return ResponseEntity.status(HttpStatus.CREATED).body(savedProduct);
}
@DeleteMapping("/{id}/cache")
public ResponseEntity<Void> evictProductCache(@PathVariable Long id) {
productService.deleteProductCache(id);
return ResponseEntity.noContent().build();
}
}
- Entity
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import static lombok.AccessLevel.PROTECTED;
@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = PROTECTED)
public class Product {
@Id
private Long id;
private String name;
private int price;
}
- Repository
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
- Serivce
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
System.out.println("최초 조회는 MariaDB에서 조회");
return productRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Product not found"));
}
public Product saveProduct(Product product) {
return productRepository.save(product);
}
@CacheEvict(value = "products", key = "#id")
public void deleteProductCache(Long id) {
System.out.println("캐시 삭제");
}
}
- 데이터는 MariaDB에 저장되고, 조회된 데이터는 Redis에 캐시 됨
- 캐시 데이터는 설정된 TTL 동안 유지되거나, 수동으로 삭제 가능
- RedisConfig
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.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.time.Duration;
@EnableCaching
@Configuration
public class RedisConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.disableCachingNullValues();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}