[Spring][MVC] RedisTemplate으로 Spring과 Redis와 연동하기
2022.02.06 - Mac M1에서 가능한 Redis GUI Client 프로그램 : Medis2
2022.02.07 - [Redis] 레디스와 캐시 그리고 데이터구조
이번엔 spring에서 redis를 어떻게 연동하는지 알아 볼 것이다.
안그래도 내가 궁금했던 패키지(?)들이다.
- data.redis.core.ReactiveStringRedisTemplate
- data.redis.core.RedisOperations
- data.redis.core.RedisTemplate
- data.redis.core.SessionCallback
그리고 일단 mvc에서 어떻게 쓰는지 간단하게 보고, 나의 메인은 webflux에서 비동기적으로 Redis를 어떻게 연결하는지 볼 것이다.
2022.02.05 - ⚽️MVC와 WebFlux의 차이점, MVC가 '벽에 공 던지기'라면 WebFlux는..?
2022.02.01 - [WebFlux] 💚 Webflux 그림으로 이해하기(Reactive프로그래밍)
Spring Data Redis 라이브러리
Redis에 접근하기 위해서 Spring Data Redis 라이브러리가 필요하다.
이때 Redis를 2가지 방식으로 접근할 수 있는 프레임워크가 있는데, Lettuce와 Jedis이다.
Lettuce는 별도의 설정없이 사용할 수 있지만, Jedis를 사용하려면 의존성을 추가해야한다.
(그런데 이 글을 보면 성능은 Jedis보다 Lettuce가 더 좋다고 한다)
그리고 Spring Data Redis 라이브러리는 2가지 접근방식을 제공한다.
- RedisTemplate을 이용한 방식
- Redis Repository를 이용한 방식
일단 나는 첫번째 template을 이용한 방식만 알아보고 실습으로 진행해보려고 한다.
의존성추가
기본적으로 mvc기반의 spring에서 redis를 사용하기 위해선 아래와 같은 라이브러리를 의존성에 추가해야한다.
implementation("org.springframework.boot:spring-boot-starter-data-redis")
참고로, webflux기반의 spring에서 redis를 사용하기 위해선 별도의 redis 라이브러리가 필요하다.
reactive redis가 아직 spring-data-redis에 통합되어 있지 않기 때문에 라이브러리를 추가해야한다.
implementation("org.springframework.boot:spring-boot-starter-data-redis-reactive")
환경설정
Redis 접근 Library는 Spring Data Redis에 내장되어있는 Lettuce를 사용하고, 환경설정은 아래와 같이 template을 따른다.
@Configuration
@EnableRedisRepositories
public class RedisConfig {
//Application.yml 값 가져옴
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
//Lettuce 사용
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
그리고 application.yml에 사용할 redis의 host(url)과 port를 설정해준다.
그럼 config에서 @Value로 그 값을 가지고 올 수 있다.
RedisTemplate, StringRedisTemplate
위에 코드에서 아주간단하게 redistemplate을 생성하는 부분은 아래와 같다.
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
RedisTemplate는 redis 서버에 redis커맨드를 수행하기 위한 high-level-abstractions을 제공한다.
또한 RedisTemplate의 Serialize, Deserialize로 String을 사용하는 StringRedisTemplate을 통해
redis 서버에 데이터 CRUD를 할 수 있는 operation inerface를 제공한다.
- opsForValue() : Redis의 String타입을 Serialize / Deserialize 해주는 인터페이스
- opsForList() : Redis의 List타입을 Serialize / Deserialize 해주는 인터페이스
- opsForSet() : Redis의 Set타입을 Serialize / Deserialize 해주는 인터페이스
- opsForZset() : Redis의 Zset타입을 Serialize / Deserialize 해주는 인터페이스
- opsForHash() : Redis의 Hash타입을 Serialize / Deserialize 해주는 인터페이스
아래의 코드는 자바에서 spring data redis를 사용해서 redis와 통신할 수 있는 코드예시이다.
일단 우선 간단하게 코드만 읽어보고, kotiln으로 그리고 mvc가 아닌 webflux에서 redis를 어떻게 구현하는지 알아보는게 목표이다.
Redis 자료구조 CRUD 예시 : String
opsForValue() 메소드를 사용해서 레디스 string 타입의 자료구조에 접근할 수 있다.
@Autowired
StringRedisTemplate redisTemplate;
@Test
public void testStrings() {
final String key = "newkey";
final ValueOperations<String, String> stringStringValueOperations = redisTemplate.opsForValue();
stringStringValueOperations.set(key, "1"); // redis set 명령어
final String result_1 = stringStringValueOperations.get(key); // redis get 명령어
System.out.println("result_1 = " + result_1);
stringStringValueOperations.increment(key); // redis incr 명령어
final String result_2 = stringStringValueOperations.get(key);
System.out.println("result_2 = " + result_2);
}
result_1 = 1
result_2 = 2
Redis 자료구조 CRUD 예시 : List
opsForList() 메소드를 사용해서 레디스 List 타입의 자료구조에 접근할 수 있다.
@Autowired
StringRedisTemplate redisTemplate;
@Test
public void testList() {
final String key = "newkey";
final ListOperations<String, String> stringStringListOperations = redisTemplate.opsForList();
stringStringListOperations.rightPush(key, "H");
stringStringListOperations.rightPush(key, "e");
stringStringListOperations.rightPush(key, "l");
stringStringListOperations.rightPush(key, "l");
stringStringListOperations.rightPush(key, "o");
stringStringListOperations.rightPushAll(key, " ", "a", "a", "b", "b");
final String character_1 = stringStringListOperations.index(key, 1);
System.out.println("character_1 = " + character_1);
final Long size = stringStringListOperations.size(key);
System.out.println("size = " + size);
final List<String> ResultRange = stringStringListOperations.range(key, 0, 9);
System.out.println("ResultRange = " + Arrays.toString(ResultRange.toArray()));
}
character_1 = e
size = 10
ResultRange = [H, e, l, l, o, , a, a, b, b]
Redis 자료구조 CRUD 예시 : Set
opsForSet() 메소드를 사용해서 레디스 set 타입의 자료구조에 접근할 수 있다.
@Test
public void testSet() {
String key = "sabarada";
SetOperations<String, String> stringStringSetOperations = redisTemplate.opsForSet();
stringStringSetOperations.add(key, "H");
stringStringSetOperations.add(key, "e");
stringStringSetOperations.add(key, "l");
stringStringSetOperations.add(key, "l");
stringStringSetOperations.add(key, "o");
Set<String> sabarada = stringStringSetOperations.members(key);
System.out.println("members = " + Arrays.toString(sabarada.toArray()));
Long size = stringStringSetOperations.size(key);
System.out.println("size = " + size);
Cursor<String> cursor = stringStringSetOperations.scan(key, ScanOptions.scanOptions().match("*").count(3).build());
while(cursor.hasNext()) {
System.out.println("cursor = " + cursor.next());
}
}
members = [l, e, o, H]
size = 4
cursor = l
cursor = e
cursor = o
cursor = H
Redis 자료구조 CRUD 예시 : Sorted Set
opsForSortedSet() 메소드를 사용해서 레디스 sorted set 타입의 자료구조에 접근할 수 있다.
@Test
public void testSortedSet() {
String key = "sabarada";
ZSetOperations<String, String> stringStringZSetOperations = redisTemplate.opsForZSet();
stringStringZSetOperations.add(key, "H", 1);
stringStringZSetOperations.add(key, "e", 5);
stringStringZSetOperations.add(key, "l", 10);
stringStringZSetOperations.add(key, "l", 15);
stringStringZSetOperations.add(key, "o", 20);
Set<String> range = stringStringZSetOperations.range(key, 0, 5);
System.out.println("range = " + Arrays.toString(range.toArray()));
Long size = stringStringZSetOperations.size(key);
System.out.println("size = " + size);
Set<String> scoreRange = stringStringZSetOperations.rangeByScore(key, 0, 13);
System.out.println("scoreRange = " + Arrays.toString(scoreRange.toArray()));
}
range = [H, e, l, o]
size = 4
scoreRange = [H, e]
Redis 자료구조 CRUD 예시 : Hash
opsForSortedHash() 메소드를 사용해서 레디스 hash 타입의 자료구조에 접근할 수 있다.
@Test
public void testHash() {
String key = "newkey";
HashOperations<String, Object, Object> stringObjectObjectHashOperations = redisTemplate.opsForHash();
stringObjectObjectHashOperations.put(key, "Hello", "newkey");
stringObjectObjectHashOperations.put(key, "Hello2", "newkey");
stringObjectObjectHashOperations.put(key, "Hello3", "newkey");
Object hello = stringObjectObjectHashOperations.get(key, "Hello");
System.out.println("hello = " + hello);
Map<Object, Object> entries = stringObjectObjectHashOperations.entries(key);s
System.out.println("entries = " + entries.get("Hello2"));
Long size = stringObjectObjectHashOperations.size(key);
System.out.println("size = " + size);
}
hello = newkey
entries = newkey2
size = 3
일단 우선 간단하게 코드만 읽어보고, kotiln으로 그리고 mvc가 아닌 webflux에서 redis를 어떻게 구현하는지 알아보는게 목표이다.
참고
https://sabarada.tistory.com/105?category=856943
https://devlog-wjdrbs96.tistory.com/375