Skip to content

Commit 456b4bd

Browse files
committed
reactive redis
1 parent c828f3a commit 456b4bd

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed

build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ dependencies {
2525
implementation 'org.springframework.boot:spring-boot-starter-web'
2626
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
2727
implementation 'org.springframework.boot:spring-boot-starter-cache'
28+
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
2829
implementation 'com.google.code.gson:gson'
2930
implementation 'com.h2database:h2'
3031
compileOnly 'org.projectlombok:lombok'
3132
runtimeOnly 'mysql:mysql-connector-java'
3233
annotationProcessor 'org.projectlombok:lombok'
3334
testImplementation 'org.springframework.boot:spring-boot-starter-test'
35+
testImplementation 'io.projectreactor:reactor-test:3.1.0.RELEASE'
3436
testCompileOnly 'org.projectlombok:lombok'
3537
}

src/main/java/com/redis/cluster/config/RedisCacheConfig.java

+7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import org.springframework.data.redis.cache.CacheKeyPrefix;
88
import org.springframework.data.redis.cache.RedisCacheConfiguration;
99
import org.springframework.data.redis.cache.RedisCacheManager;
10+
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
1011
import org.springframework.data.redis.connection.RedisConnectionFactory;
12+
import org.springframework.data.redis.core.ReactiveRedisTemplate;
1113
import org.springframework.data.redis.core.RedisTemplate;
1214
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
1315
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
@@ -55,4 +57,9 @@ public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFacto
5557
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
5658
return redisTemplate;
5759
}
60+
61+
@Bean
62+
public ReactiveRedisTemplate<String, String> reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory) {
63+
return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
64+
}
5865
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package com.redis.cluster;
2+
3+
import com.redis.cluster.repo.redis.StudentRedisRepo;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.boot.test.context.SpringBootTest;
10+
import org.springframework.data.geo.Point;
11+
import org.springframework.data.redis.connection.DataType;
12+
import org.springframework.data.redis.core.*;
13+
import org.springframework.test.context.junit4.SpringRunner;
14+
import reactor.core.publisher.Mono;
15+
import reactor.test.StepVerifier;
16+
17+
import java.util.*;
18+
19+
@RunWith(SpringRunner.class)
20+
@SpringBootTest
21+
public class ReactiveRedisClusterTest {
22+
23+
private Logger log = LoggerFactory.getLogger(this.getClass());
24+
25+
26+
@Autowired
27+
private RedisTemplate<String, String> redisTemplate;
28+
29+
@Autowired
30+
private ReactiveRedisTemplate<String, String> reactiveRedisTemplate;
31+
32+
@Autowired
33+
private StudentRedisRepo redisRepo;
34+
35+
/**
36+
* 문자 데이터 구조 처리
37+
*/
38+
@Test
39+
public void opsValue() {
40+
ReactiveValueOperations<String, String> valueOps = reactiveRedisTemplate.opsForValue();
41+
Set<String> cacheKeys = new HashSet<>();
42+
Map<String, String> setDatas = new HashMap<>();
43+
for (int i = 0; i < 10; i++) {
44+
String key = "value_" + i;
45+
cacheKeys.add(key);
46+
setDatas.put(key, String.valueOf(i));
47+
}
48+
// previous key delete - sync
49+
redisTemplate.delete(cacheKeys);
50+
51+
// async
52+
Mono<Boolean> results = valueOps.multiSet(setDatas);
53+
StepVerifier.create(results).expectNext(true).verifyComplete();
54+
55+
Mono<List<String>> values = valueOps.multiGet(cacheKeys);
56+
StepVerifier.create(values)
57+
.expectNextMatches(x -> x.size() == 10).verifyComplete();
58+
}
59+
60+
/**
61+
* List 데이터 구조 처리 - 순서 있음. value 중복 허용
62+
*/
63+
@Test
64+
public void opsList() {
65+
ReactiveListOperations<String, String> listOps = reactiveRedisTemplate.opsForList();
66+
String cacheKey = "valueList";
67+
68+
// previous key delete
69+
redisTemplate.delete(cacheKey);
70+
71+
// async
72+
Mono<Long> results = listOps.leftPushAll(cacheKey, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
73+
StepVerifier.create(results).expectNext(10L).verifyComplete();
74+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.LIST).verifyComplete();
75+
StepVerifier.create(listOps.size(cacheKey)).expectNext(10L).verifyComplete();
76+
StepVerifier.create(listOps.rightPop(cacheKey)).expectNext("0").verifyComplete();
77+
StepVerifier.create(listOps.leftPop(cacheKey)).expectNext("9").verifyComplete();
78+
}
79+
80+
/**
81+
* Hash 데이터 구조 처리 - 순서 없음. key 중복허용 안함, value 중복 허용
82+
*/
83+
@Test
84+
public void opsHash() {
85+
ReactiveHashOperations<String, String, String> hashOps = reactiveRedisTemplate.opsForHash();
86+
String cacheKey = "valueHash";
87+
Map<String, String> setDatas = new HashMap<>();
88+
for (int i = 0; i < 10; i++) {
89+
setDatas.put("key_" + i, "value_" + i);
90+
}
91+
92+
// previous key delete - sync
93+
redisTemplate.delete(cacheKey);
94+
95+
// async
96+
StepVerifier.create(hashOps.putAll(cacheKey, setDatas)).expectNext(true).verifyComplete();
97+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.HASH).verifyComplete();
98+
StepVerifier.create(hashOps.size(cacheKey)).expectNext(10L).verifyComplete();
99+
StepVerifier.create(hashOps.get(cacheKey, "key_5")).expectNext("value_5").verifyComplete();
100+
StepVerifier.create(hashOps.remove(cacheKey, "key_5")).expectNext(1L).verifyComplete();
101+
}
102+
103+
/**
104+
* Set 데이터 구조 처리 - 순서 없음, value 중복 허용 안함
105+
*/
106+
@Test
107+
public void opsSet() {
108+
ReactiveSetOperations<String, String> setOps = reactiveRedisTemplate.opsForSet();
109+
String cacheKey = "valueSet";
110+
111+
// previous key delete - sync
112+
redisTemplate.delete(cacheKey);
113+
114+
// async
115+
for (int i = 0; i < 10; i++)
116+
StepVerifier.create(setOps.add(cacheKey, String.valueOf(i))).expectNext(1L).verifyComplete();
117+
118+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.SET).verifyComplete();
119+
StepVerifier.create(setOps.size(cacheKey)).expectNext(10L);
120+
StepVerifier.create(setOps.isMember(cacheKey, "5")).expectNext(true);
121+
}
122+
123+
/**
124+
* SortedSet 데이터 구조 처리 - 순서 있음, value 중복 허용 안함
125+
*/
126+
@Test
127+
public void opsSortedSet() {
128+
ReactiveZSetOperations<String, String> zsetOps = reactiveRedisTemplate.opsForZSet();
129+
String cacheKey = "valueZSet";
130+
131+
// previous key delete - sync
132+
redisTemplate.delete(cacheKey);
133+
134+
// async
135+
for (int i = 0; i < 10; i++)
136+
StepVerifier.create(zsetOps.add(cacheKey, String.valueOf(i), i)).expectNext(true).verifyComplete();
137+
138+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.ZSET).verifyComplete();
139+
StepVerifier.create(zsetOps.size(cacheKey)).expectNext(10L).verifyComplete();
140+
StepVerifier.create(zsetOps.reverseRank(cacheKey, "9")).expectNext(0L).verifyComplete();
141+
}
142+
143+
/**
144+
* Geo 데이터 구조 처리 - 좌표 정보 처리, 타입은 zset으로 저장.
145+
*/
146+
@Test
147+
public void opsGeo() throws Exception {
148+
GeoOperations<String, String> geoOpsSync = redisTemplate.opsForGeo();
149+
ReactiveGeoOperations<String, String> geoOps = reactiveRedisTemplate.opsForGeo();
150+
String[] cities = {"서울", "부산"};
151+
String[] gu = {"강남구", "서초구", "관악구", "동작구", "마포구", "사하구", "해운대구", "영도구", "동래구", "수영구"};
152+
String cacheKey = "valueGeo";
153+
154+
// previous key delete - sync
155+
redisTemplate.delete(cacheKey);
156+
157+
for (int x = 0; x < cities.length; x++) {
158+
for (int y = 0; y < gu.length / 2; y++) {
159+
geoOpsSync.add(cacheKey, new Point(x, y), gu[x * y]);
160+
}
161+
}
162+
// async
163+
StepVerifier.create(geoOps.distance(cacheKey, "강남구", "동작구")).expectNextMatches(x -> x.getValue() == 333678.8605).verifyComplete();
164+
StepVerifier.create(geoOps.position(cacheKey, "동작구")).expectNextMatches(x -> x.getX() == 0.9999999403953552 && x.getY() == 3.0000009121501066).verifyComplete();
165+
}
166+
167+
/**
168+
* HyperLogLog 데이터 구조 처리 - 집합의 원소의 개수 추정, 타입은 string으로 저장.
169+
*/
170+
@Test
171+
public void opsHyperLogLog() {
172+
ReactiveHyperLogLogOperations<String, String> hyperLogLogOps = reactiveRedisTemplate.opsForHyperLogLog();
173+
String cacheKey = "valueHyperLogLog";
174+
175+
// previous key delete - sync
176+
redisTemplate.delete(cacheKey);
177+
178+
// async
179+
String[] arr = {"1", "2", "2", "3", "4", "5", "5", "5", "5", "6", "7", "7", "7"};
180+
StepVerifier.create(hyperLogLogOps.add(cacheKey, arr)).expectNext(1L).verifyComplete();
181+
StepVerifier.create(hyperLogLogOps.size(cacheKey)).expectNext(7L).verifyComplete();
182+
}
183+
}

0 commit comments

Comments
 (0)