[Springboot] '์ตœ๊ทผ ์ฝ์€ ๊ธ€' Dto๋กœ Redis์— ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๊ธฐ AtoZ (2) - ์ˆ˜์ •, ์‚ญ์ œ ํŽธ

2021. 6. 24. 17:01ใ†๐ŸŒฑ Develop/Server

2021.06.18 - [๐ŸŒฑ Develop/Server] - [Springboot] '์ตœ๊ทผ ์ฝ์€ ๊ธ€' Dto๋กœ Redis์— ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๊ธฐ AtoZ

 

[Springboot] '์ตœ๊ทผ ์ฝ์€ ๊ธ€' Dto๋กœ Redis์— ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๊ธฐ AtoZ

โ“ redis ๋ฅผ ์„ ํƒํ•œ ์ด์œ  ๋ธ”๋กœ๊ทธ ํ™ˆํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“œ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ, "์ตœ๊ทผ ์ฝ์€ ๊ธ€" ์„ ๊ฐœ๋ฐœํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. velog ๊ฐ™์€ ์„œ๋น„์Šค์—์„œ๋Š” ๊ฝค ์˜ค๋žœ ๊ธฐ๊ฐ„๋™์•ˆ ๋‚ด๊ฐ€ ์ฝ์€ ๊ธ€์„ ์ €์žฅํ•˜๋Š” ๋“ฏ ํ–ˆ

tape22.tistory.com

์ด์ „ ๊ธ€์—์„œ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ redis์— list๋กœ ์กฐํšŒํ•œ ๊ธ€ Dto๋ฅผ ์ €์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ํ”„๋ก ํŠธ์— ๋ฐฐํฌ๋ฅผ ํ•˜๊ณ  ๋‚˜๋‹ˆ, ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์ด์Šˆ๋ฅผ ๊ฐ„๊ณผํ•˜๊ณ  ์žˆ์–ด์„œ ๋‘ ๋ฒˆ์งธ ๊ธ€์„ ์“ฐ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋กœ์ง์œผ๋กœ๋Š” postIdx ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น post ์กฐํšŒ ๊ฐ’์„ Dto๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ์ด Dto๋ฅผ list์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ธ๋ฐ, "์กฐํšŒ ๋‚ด์šฉ ๊ฒฐ๊ณผ"๋ฅผ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

  • post ์› ๊ธ€์ด ์ˆ˜์ •, ์‚ญ์ œ๋˜์—ˆ์„ ๋•Œ ๋‚ด์šฉ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค.
  • list๋Š” ์ค‘๋ณต์„ ํ—ˆ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ๊ธ€์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ์œผ๋ฉด ๋˜‘๊ฐ™์€ ๊ธ€์ด redis์— ์Œ“์ธ๋‹ค.

๊ทธ๋ž˜์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ List ํƒ€์ž…์—์„œ '์ •๋ ฌ์ด ๊ฐ€๋Šฅํ•œ set ํƒ€์ž…'์ธ zSet ๋กœ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ , ์ตœ๊ทผ ์ฝ์€ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌํ•˜๋„๋ก ๋ณ€๊ฒฝ

๐Ÿ“Œ ์กฐํšŒ ๋‚ด์šฉ ๊ฒฐ๊ณผ ์ €์žฅ์ด ์•„๋‹ˆ๋ผ postIdx๋ฅผ redis์— ์ €์žฅ

1. RecentLog ์ˆ˜์ •

๋จผ์ € recentLog ๋„๋ฉ”์ธ๋ถ€ํ„ฐ ์ˆ˜์ •ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด์ „์—๋Š” userIdx์™€ postDto.ListDto ๋ฅผ ์ €์žฅํ•˜๋„๋ก ํ–ˆ์ง€๋งŒ, ์ง€๊ธˆ์€ postIdx๋ฅผ ์ €์žฅํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— Long ํƒ€์ž…์œผ๋กœ ์ˆ˜์ •ํ•ด์ค๋‹ˆ๋‹ค.

 

๐Ÿ“‚  domain/RecentLog

@RedisHash("userIdx")
@Getter @ToString @NoArgsConstructor @AllArgsConstructor @Builder
public class RecentLog {

    @Id
    private  Long userIdx;
    private  Long postIdx;

}

2. Service

1๏ธโƒฃ Redis์— ์ €์žฅํ•˜๊ธฐ

RedisTemplate ๋„ <String, PostDto.List> ์—์„œ <String, RecentLog> ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , opsForList() ๋ฅผ opsForZSet() ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ค๋‹ˆ๋‹ค. RedisTemplate ์—๋Š” ๋‹ค์–‘ํ•œ ๋ฉ”์†Œ๋“œ๋“ค ์ค€๋น„๋˜์–ด ์žˆ๋Š”๋ฐ, RedisTemplate๋กœ ๋“ค์–ด๊ฐ€๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋“ค์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ž์„œ ๋งํ–ˆ๋“ฏ์ด, Set์ด ์•„๋‹ˆ๋ผ ZSet์„ ๊ณ ๋ฅธ ์ด์œ ๋Š” '์ˆœ์„œ'๊ฐ€ ์žˆ๊ณ  ์—†๊ณ ์˜ ์ฐจ์ด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด์„œ Set์œผ๋กœ postIdx๋ฅผ ์ €์žฅํ•˜๋ฉด ์ฝ์€ ์ˆœ์„œ์™€ ์ƒ๊ด€์—†์ด ์ €์žฅ์ด ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ '์ตœ๊ทผ ์ฝ์€ ๊ธ€'์€ ๋‚ด๊ฐ€ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ฝ์€ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ์ด ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ZSet์œผ๋กœ ์„ค์ •ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‚ listService

    private final PostMapper postMapper;
    private final PostRepository postRepository;
    private final RedisTemplate<String, RecentLog> redisTemplate;

    // ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์ €์žฅ -> set์œผ๋กœ ๋ณ€๊ฒฝ, postIdx ์ €์žฅ
    @Transactional
    public void saveRecentReadPosts(Long userIdx, Long postIdx){
        ZSetOperations<String, RecentLog> zSetOps = redisTemplate.opsForZSet();
        RecentLog recentLog = RecentLog.builder().userIdx(userIdx).postIdx(postIdx).build();
        zSetOps.add(setKey(userIdx), recentLog, new java.util.Date().getTime()); // score์€ ํƒ€์ž„์Šคํƒฌํ”„(์ตœ์‹  ์ฝ์€ ์ˆœ๋Œ€๋กœ ์ •๋ ฌ์œ„ํ•ด)
        redisTemplate.expireAt(setKey(userIdx), Date.from(ZonedDateTime.now().plusDays(7).toInstant())); // ์œ ํšจ๊ธฐ๊ฐ„ TTL ์ผ์ฃผ์ผ ์„ค์ •
    }
  • zSetOps์—๋Š” add๋ฅผ ํ•  ๋•Œ (key ๊ฐ’, ์ €์žฅํ•  ๊ฐ’, score) ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „๊ณผ ๋‹ฌ๋ฆฌ score์ด๋ž€ ๊ฐ’์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ score์€ ๊ฐ’์„ ์ •๋ ฌ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฐ’์œผ๋กœ, ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด userIdx::2๋ผ๋Š” "key"๋กœ ์กฐํšŒํ•˜๋ฉด key(recentLog) : value (score)์˜ set ๊ฐ’์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
  • list ๋•Œ์™€ ๋™์ผํ•˜๊ฒŒ redisTemplate๋กœ ์œ ํšจ๊ธฐ๊ฐ„์„ 7์ผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

2๏ธโƒฃ Redis์—์„œ ์กฐํšŒํ•˜๊ธฐ

๋‹ค์Œ์€ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‚ listService

  // ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ
    @Transactional
    public List<PostDto.ListResponse> findRecentPosts(Long userIdx) {
        ZSetOperations<String, RecentLog> zSetOps = redisTemplate.opsForZSet();
        ObjectMapper objectMapper = new ObjectMapper(); // linkedHashMap์œผ๋กœ ์ €์žฅ๋œ redis ๊ฐ’๋“ค์„ List๋กœ ๋ณ€ํ™˜ํ•ด์คŒ
        List<RecentLog> result = objectMapper.convertValue(Objects.requireNonNull(zSetOps.reverseRange(setKey(userIdx), 0, -1)),
                new TypeReference<List<RecentLog>>() {
        });
        return result.stream().map(x -> postMapper.postToListResponse(findPostById(x.getPostIdx()), userIdx)).collect(Collectors.toList());

    }


     private String setKey(Long userIdx){
        return "userIdx::"+userIdx;
    }
  • zSetOps์—์„œ reverseRange๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์žฅ ๋‚˜์ค‘์— ์ถ”๊ฐ€๋œ ๊ธ€( == ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ฝ์€ ๊ธ€)์„ ๋จผ์ € ์˜ค๋„๋ก ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. reverseRange(key๊ฐ’, ์‹œ์ž‘ ์ธ๋ฑ์Šค, ๋ ์ธ๋ฑ์Šค)๋ฅผ ์„ค์ •ํ•˜์—ฌ ํ•œ๊บผ๋ฒˆ์— ๊ฐ’์„ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์ด๋Œ€๋กœ Redis์—์„œ ์กฐํšŒํ•œ ๊ฐ’์„ map์œผ๋กœ dto ๋ณ€ํ™˜ํ•˜๋ คํ•˜๋ฉด ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.
    java.util.LinkedHashMap cannot be cast to ......List๋‚˜ dto.....ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ์ด์œ ๋Š” redis์—์„œ๋Š” LinkedHashMap์œผ๋กœ ๊ฐ’์ด ์ €์žฅ๋˜๋Š”๋ฐ, zSetOperations ๋กœ ์ €์žฅํ•˜๋ฉด [ {ํ•˜๋‚˜}, {๋‘˜}, {์…‹} ]... ์ด๋Ÿฐ ์‹์œผ๋กœ ์ €์žฅ๋˜์–ด ์กฐํšŒ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ๋ฐฐ์—ด์„ ๊ฐ–๊ณ ์™€์„œ dto๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๊ณ  ํ•˜๋ฉด,์—๋Ÿฌ๋ฅผ ๋งž์ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ objectMapper์„ ์‚ฌ์šฉํ•ด์„œ LinkedHashMap์„ list๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค, dto๋กœ ๋‹ค์‹œ ๋ฐ”๊ฟ”์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.
  • ObjectMapper objectMapper = new ObjectMapper(); // linkedHashMap์œผ๋กœ ์ €์žฅ๋œ redis ๊ฐ’๋“ค์„ List๋กœ ๋ณ€ํ™˜ํ•ด์คŒ List<RecentLog> result = objectMapper.convertValue(Objects.requireNonNull(zSetOps.reverseRange(setKey(userIdx), 0, -1)), new TypeReference<List<RecentLog>>() { });
  • ์ด ์ดํ›„๋กœ๋Š” ํ‰์†Œ ํ•˜๋˜๋Œ€๋กœ list๋ฅผ dto๋กœ ๋ฐ”๊พธ์–ด ๋ฆฌํ„ดํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

3๏ธโƒฃ ์›๊ธ€ ์‚ญ์ œ ์‹œ redis์—์„œ๋„ ๊ฐ’ ์‚ญ์ œ 

์›๊ธ€์˜ ์ˆ˜์ •์‚ฌํ•ญ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ ์™ธ์—๋„, ๊ธ€์ด ์‚ญ์ œ๋˜๋ฉด "์ตœ๊ทผ ์กฐํšŒํ•œ ๊ธ€" ๋ชฉ๋ก์—์„œ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์‚ญ์ œ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฒˆ์—๋Š” postService๋ฅผ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

๐Ÿ“‚ postService

  // ํšŒ๊ณ ๊ธ€ ์‚ญ์ œ
    @Transactional
    public boolean deletePosts(Long userIdx,Long postIdx) {
        Post post = postRepository.findById(postIdx)
                .orElseThrow(() -> new EntityNullException(ErrorInfo.POST_NULL));
        if (isWriter(post.getUser().getUserIdx(), userIdx)){
            postRepository.deleteById(postIdx);
            if (listService.isPostsExist(userIdx, postIdx)) listService.deleteRedisPost(userIdx, postIdx); // redis ์—์„œ๋„ ์‚ญ์ œ
            return true;
        }
        return false;
    }
  • isPostExist ๋ฉ”์†Œ๋“œ๋กœ "Redis์— ํ•ด๋‹น postIdx" ๊ฐ€ ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. 
  • ๋งŒ์•ฝ ๊ธ€์ด ์žˆ์œผ๋ฉด ์›๊ธ€์ด ์‚ญ์ œ๋  ๋•Œ Redis์—์„œ๋„ ๊ฐ™์ด ์‚ญ์ œํ•ด์ฃผ๋Š” deleteRedisPost ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‚ listService

Redis์— ๊ฐ’์ด ์กด์žฌํ•˜๋Š”์ง€ ์ฒดํฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค. "์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ" ์™€ ๋™์ผํ•˜๊ฒŒ Redis์— ์žˆ๋Š” ๋ชฉ๋ก๋“ค์„ ๊ฐ€์ ธ์™€์„œ ํ•ด๋‹น postIdx๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š”์ง€ ํŒ๋ณ„ํ•ฉ๋‹ˆ๋‹ค. 

 public boolean isPostsExist(Long userIdx, Long postIdx){
        ZSetOperations<String, RecentLog> zSetOps = redisTemplate.opsForZSet();
        RecentLog recentLog = RecentLog.builder().userIdx(userIdx).postIdx(postIdx).build();
        ObjectMapper objectMapper = new ObjectMapper();
        List<RecentLog> result = objectMapper.convertValue(Objects.requireNonNull(zSetOps.reverseRange(setKey(userIdx), 0, -1)),
                new TypeReference<List<RecentLog>>() {
                });
        return result.contains(recentLog);
    }

์‚ญ์ œํ•  ๋•Œ๋Š” RecentLog ๊ฐ’์„ ์‹ค์ œ key๋กœ ์ €์žฅํ–ˆ์œผ๋ฏ€๋กœ, key๋ฅผ ์ฐพ์•„ ์‚ญ์ œํ•˜๋Š” remove ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์ค๋‹ˆ๋‹ค.

    // redis์—์„œ value ์‚ญ์ œ
    public void deleteRedisPost(Long userIdx,Long postIdx){
        ZSetOperations<String, RecentLog> zSetOps = redisTemplate.opsForZSet();
        RecentLog recentLog = RecentLog.builder().userIdx(userIdx).postIdx(postIdx).build();
        zSetOps.remove(setKey(userIdx), recentLog);
    }

 

3. ๊ฒฐ๊ณผ

swagger์—์„œ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ userIdx๋Š” accessToken์—์„œ ๋ฐ›๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ๋„˜๊ฒจ์ฃผ๋Š” ๊ฐ’ ์—†์ด ์‹คํ–‰๋งŒ ์‹œ์ผœ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

{
  "statusCode": 200,
  "responseMessage": "์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ ์„ฑ๊ณต",
  "data": [
    {
      "postIdx": 67,
      "title": "KB ์นด๋“œ ๊ณต๋ชจ์ „์„ ํ•˜๋ฉด์„œ ์ง„ํ–‰ํ–ˆ๋˜ ํšŒ์˜๋“ค์„ ํšŒ๊ณ ํ•˜๊ณ ์žํ•œ๋‹ค.",
      "category": "plan",
      "contents": "<div contenteditable=\"true\" class=\"tui-editor-contents\" style=\"min-height: 168px;\"><h1><div>1. Drop<br></div></h1><ul><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">๋Š˜์–ด์ง€๋Š” ํšŒ์˜์‹œ๊ฐ„</span><br></li><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">๋ฏธ์ˆ™ํ•œ ์ค€๋น„์ƒํƒœ</span><br></li><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">๊ฐ์ •์ ์ธ ๋ฐ˜์‘๋“ค</span><br></li><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">๊ฐœ๊ฐœ์ธ์˜ ํ”ผ๊ณคํ•œ ์ƒํƒœ</span><br><br></li></ul><h1><div>2. Add<br></div></h1><ul><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">ํšŒ์˜ ์•ˆ๊ฑด์„ ์ œ์ž‘ํ•˜์—ฌ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํšŒ์˜ ์ง„ํ–‰</span><br></li></ul><div><br></div><h1><div>3. Keep<br></div></h1><ul><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">ํŽธํ•˜๊ฒŒ ์˜๊ฒฌ์„ ๊ณต์œ ํ•˜๋Š” ๋ถ„์œ„๊ธฐ</span><br></li><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">ํšŒ์˜ ํ›„ ๋น ๋ฅธ ์ •๋ฆฌ ๋ฐ ํ”ผ๋“œ๋ฐฑ</span><br></li></ul><div><br></div><h1><div>4. Improve<br></div></h1><ul><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">ํŽธํ•˜๊ฒŒ ์˜๊ฒฌ์„ ๊ณต์œ ํ•˜์ง€๋งŒ, ์ค€๋น„๋Š” ์ฒ ์ €ํ•˜๊ฒŒํ•  ๊ฒƒ</span><br></li><li><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">โ€‹</span><span class=\"colour\" style=\"color: rgb(0, 0, 0);\">ํšŒ์˜ ํ›„ ์ •๋ฆฌ๊ฐ€ ๋น ๋ฅธ ๋งŒํผ ์ค‘๊ฐ„ ์ž๋ฃŒ ๊ณต์œ ๋•Œ๋„ ์ฒด๊ณ„์ ์œผ๋กœ ์ •๋ฆฌํ•˜๊ธฐ</span><br><br></li></ul><div><br></div><div><br></div></div><div><br></div>",
      "nickname": "์žผ๋ฏผ",
      "profile": "https://s3doraboda.s3.ap-northeast-2.amazonaws.com/images/7/profiles/%EA%B3%A0%EC%96%91%EC%9D%B4.jpg",
      "tagList": [
        {
          "tag": "ํŽ˜๋ฅด์†Œ๋‚˜์—์„œ์‹œ์ž‘ํ•˜๊ธฐ"
        }
      ],
      "view": 242,
      "createdAt": "May 30, 2021",
      "commentCnt": 3,
      "scrapCnt": 4,
      "scrap": true
    },
    {
      "postIdx": 153,
      "title": "์ด๋ฏธ์ง€ ์ž„์‹œ์ €์žฅ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.",
      "category": "develop",
      "contents": "์„œ๋ฒ„!์—ด์ •!์—ด์ •!์—ด์ •!ํ†ต์‹ !ํ†ต์‹ !ํ†ต์‹ !์œผ์•„์•„!",
      "nickname": "์ฉก",
      "profile": "https://s3doraboda.s3.ap-northeast-2.amazonaws.com/images/2/profiles/%E1%84%8B%E1%85%AE%E1%86%BA%E1%84%8B%E1%85%A5%3F.jpeg",
      "tagList": [
        {
          "tag": "์‚ด๋ ค์ค˜"
        },
        {
          "tag": "ํ•  ์ˆ˜ ์žˆ์–ด"
        }
      ],
      "view": 18,
      "createdAt": "Jun 11, 2021",
      "commentCnt": 0,
      "scrapCnt": 0,
      "scrap": false
    },
    {
      "postIdx": 120,
      "title": "sdf",
      "category": "marketing",
      "contents": "<div class=\"tui-editor-contents\" style=\"min-height: 168px;\"><h1><div>1. Plus<br></div></h1><div><br></div><div><br></div><h1><div>2. Minus<br></div></h1><div><br></div><div><br></div><h1><div>3. Interesting<br></div></h1><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div></div>",
      "nickname": "์  ๋“์ด",
      "profile": "https://s3doraboda.s3.ap-northeast-2.amazonaws.com/images/3/profiles/img_20190529_001242.jpg",
      "tagList": [
        {
          "tag": "lala"
        }
      ],
      "view": 85,
      "createdAt": "Jun 11, 2021",
      "commentCnt": 3,
      "scrapCnt": 1,
      "scrap": false
    }
  ]
}

์›น ํŽ˜์ด์ง€ ์ ์šฉ ํ™”๋ฉด

๐Ÿค” ์ตœ๊ทผ ์ฝ์€ ๊ธ€ ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ํ˜„์žฌ ๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•œ ๋ถ€๋ถ„์€, redis์— ๊ฐ’์ด ์กด์žฌํ•˜๋Š”์ง€ ์ฒดํฌํ•˜๋Š” ๋ถ€๋ถ„์—์„œ "์ตœ๊ทผ ์ฝ์€ ๊ธ€ ์กฐํšŒ" ๊ธฐ๋Šฅ๊ณผ ๋™์ผํ•˜๊ฒŒ ๋“ค์–ด๊ฐ„๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ด์™ธ์—๋„ ์ค‘๋ณต๋˜๋Š” ์š”์†Œ๋“ค์ด ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ์ด ์žˆ์–ด์„œ ๋ฉ”์†Œ๋“œ๋กœ ๋”ฐ๋กœ ๋นผ๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€์ง€ ๋ณด๊ณ ,๋™์•„๋ฆฌ ๋ฐœํ‘œ ์ดํ›„๋กœ ์ˆ˜์ •ํ•ด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 

 

 

 

๐Ÿ“š ์ฐธ๊ณ ๋ฌธํ—Œ

http://blog.zepinos.com/java-redis/2017/09/09/Redis-ZSET-01.html

 

zepinos BLOG

zepinos SW Developer Blog.

blog.zepinos.com

https://effectivesquid.tistory.com/entry/Spring%EC%97%90%EC%84%9C-Redis-ZSET%EA%B5%AC%EC%A1%B0-%EC%9D%B4%EC%9A%A9%ED%95%98%EA%B8%B0

 

Spring์—์„œ Redis ZSET๊ตฌ์กฐ ์ด์šฉํ•˜๊ธฐ

Redis์˜ ZSET๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•˜์—ฌ LEADER BOARD ๊ตฌํ˜„ํ•˜๊ธฐ @Repository public class LeaderBoardRedisRepository { public static final String KEY = "leaderBoard"; @Autowired private RedisTemplate redisTemplate..

effectivesquid.tistory.com

https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/ZSetOperations.html

 

ZSetOperations (Spring Data Redis 2.5.2 API)

Set reverseRangeByScore(K key, double min, double max, long offset, long count) Get elements in range from start to end where score is between min and max from sorted set ordered high -> low.

docs.spring.io