Redis 기초 실습 & Spring Boot 적용

이진일·2026년 5월 8일
post-thumbnail

🚀 [Redis] 실전 시나리오로 배우는 자료구조 활용법

단순한 이론 공부를 넘어, 실제 서비스(블로그 조회수, 랭킹)에서 Redis 명령어가 어떻게 활용되는지 실습해 보겠습니다.


1. 단순 조회수 관리 (String 활용)

시나리오: 블로그 글(/articles/{id})에 접속할 때마다 로그인 여부와 관계없이 조회수가 1씩 증가합니다.

  • 선정 데이터 타입: String
  • 이유: 정수 데이터에 대해 INCR 연산을 지원하여 원자적(Atomic)인 증가가 가능하기 때문입니다.
# 1번 글 조회수 증가
INCR articles:1

# 2번 글 조회수 증가
INCR articles:2

# [Tip] 날짜별 조회수 관리 시
INCR articles:1:today
# 날짜가 바뀌는 시점에 키 이름 변경
RENAME articles:1:today articles:1:2026-05-08

2. 유니크 방문자 및 인기 글 랭킹 (Set & Sorted Set 활용)

시나리오: 로그인한 사용자(영문 계정)의 중복 없는 조회수와 전체 인기 글 순위를 확인합니다.

  • 선정 데이터 타입: Set(중복 제거), Sorted Set(순위 정렬)
# 1. 특정 글에 방문한 유저 기록 (중복 방지)
SADD articles:1 alex
SADD articles:1 brad
SADD articles:1 chad

# 해당 글의 유니크 방문자 수 확인
SCARD articles:1

# 2. 전체 인기 글 랭킹 관리 (Sorted Set)
# 1번 글에 조회수 1 추가
ZINCRBY articles:ranks 1 articles:1
# 2번 글에 조회수 1 추가
ZINCRBY articles:ranks 1 articles:2

# 3. 랭킹 조회
# 전체 순위 확인 (오름차순)
ZRANGE articles:ranks 0 -1
# 가장 높은 조회수를 기록한 글 1개 조회 (내림차순)
ZREVRANGE articles:ranks 0 0

3. Spring Boot에서 Redis 실전 적용

앞서 다룬 시나리오들을 실제 Spring Boot 프로젝트에 구현해 봅시다.

🔹 Case A. RedisRepository를 이용한 주문(Order) CRUD

JPA 스타일로 주문 데이터를 Hash 자료구조에 저장하는 방식입니다.

ItemOrder.java (Domain)

@Getter @Setter @Builder
@NoArgsConstructor @AllArgsConstructor
@RedisHash("order")
public class ItemOrder {
    @Id
    private String id;
    private String item;
    private Integer count;
    private Long totalPrice;
    private String status;
}

OrderController.java

@RestController
@RequestMapping("orders")
public class OrderController {
	private final OrderRepository orderRepository;

	public OrderController(OrderRepository orderRepository) {
		this.orderRepository = orderRepository;
	}

	@PostMapping
	public ItemOrder create(@RequestBody ItemOrder order) {
		return orderRepository.save(order);
	}

	@GetMapping
	public List<ItemOrder> readAll() {
		List<ItemOrder> orders = new ArrayList<>();
		orderRepository.findAll()
			.forEach(orders::add);

		return orders;
	}

	@GetMapping("/{id}")
	public ItemOrder readOne(@PathVariable("id") String id) {
		return orderRepository.findById(id)
			.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
	}

	@PutMapping("/{id}")
	public ItemOrder update(@PathVariable String id, @RequestBody ItemOrder order) {
		ItemOrder target = orderRepository.findById(id)
			.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
		target.setItem(order.getItem());
		target.setCount(order.getCount());
		target.setTotalPrice(order.getTotalPrice());
		target.setStatus(order.getStatus());
		return orderRepository.save(target);
	}

	@DeleteMapping("/{id}")
	public void delete(@PathVariable("id") String id) {
		orderRepository.deleteById(id);
	}
}

Postman같은 클라이언트로 API를 호출해보면 Redis에 데이터가 CRUD되는 것을 확인할 수 있습니다.

🔹 Case B. RedisTemplate을 이용한 조회수 로직 구현

원하는 키 형식을 직접 제어하고 increment 기능을 활용합니다.

RedisConfig.java
조회수(Integer)를 처리하기 위해 GenericToStringSerializer를 활용한 설정입니다.

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Integer> articleTemplate(RedisConnectionFactory connectionFactory) {
       RedisTemplate<String, Integer> template = new RedisTemplate<>();
       template.setConnectionFactory(connectionFactory);
       template.setKeySerializer(RedisSerializer.string());
       template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
       return template;
    }
}

ArticleController.java

@RestController
@RequestMapping("articles")
public class ArticleController {
    private final ValueOperations<String, Integer> ops;

    public ArticleController(RedisTemplate<String, Integer> articleTemplate) {
       ops = articleTemplate.opsForValue();
    }

    @GetMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void read(@PathVariable("id") Long id) {
       // 접속 시마다 Redis의 articles:{id} 키 값 증가
       ops.increment("articles:%d".formatted(id));
    }
}

💡 실습 마무리

이번 실습을 통해 Redis의 기본 명령어가 Spring Boot 환경에서 어떻게 코드로 녹아드는지 살펴보았습니다.

  • Repository는 객체 단위의 영속성이 필요할 때,

  • Template은 특정 데이터 구조의 기능을 세밀하게 사용해야 할 때(예: 조회수 증가) 적합합니다.

0개의 댓글