생각정리/Redis
Spring Redis 자료구조 사용
생각중임
2024. 2. 19. 17:00
의존성 주입
gradle에 redis의존성을 추가해 준다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
레디스 주소 설정
레디스를 사용할 호스트주소와 포트번호를 지정해 준다.
spring:
data:
redis:
host: localhost
port: 6379
레디스 설정
Lettuce Client를 이용해 Redis와 연결하고 사용하기 편하게 Redis Template를 수정해 사용을 한다.
크게 사용하는 시리얼라이저는 3가지로 프로젝트와 개인에 맞게 설정해서 사용을 하는 듯하다.
- GenericJackson2JsonRedisSerializer
- 제일 많이 사용하는 방법으로 class type에 상관없이 값을 불러올 수 있다.
- 저장 시 클래스 패키지 명등 클래스 타입 전체를 저장하여 해당 패키지 dto가 아닐 경우, key값을 조회할 수 없다
- Jackson2JsonRedisSerializer
- 클래스 정보를 RedisTemplate dto추가될 때마다 Bean을 생성해줘야 한다.
- StringRedisSerializer
- Jsackson의 Objectmapper를 이용해 json과 string을 서로 변환하여 사용한다.
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
// template를 주입할 때 자료형을 지정하기 위해 <?, ?>로 한다.
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
// JSON 포맷으로 데이터를 저장하는 경우
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
// 일반적인 key:value일 때
redisTemplate.setDefaultSerializer(new StringRedisSerializer());
// Hash를 사용할 경우
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
Redis 자료구조
Redis 자료구조 | 메소드명 | 반환 오퍼레이션 |
String | opsForValue() | ValueOperations |
List | opsForList() | ListOperations |
Set | opsForSet() | SetOperations |
Sorted Set | opsForZSet() | ZSetOperations |
Hash | opsForHash() | HashOperations |
String
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private final RedisTemplate<String, Object> redisTemplate;
// String 저장
public void save(String key, String value) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value);
}
// String 조회
public String getValue(String key) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
return (String) valueOperations.get(key);
}
}
@Service
@RequiredArgsConstructor
public class Service {
private final RedisRepository redisRepository;
// String 저장
public void save(String key, String value) {
for (int i = 0; i < 5; i++) {
redisRepository.save("key:"+ key + ":" + i, value + i);
}
}
// String 조회
public String getValue(String key) {
return redisRepository.getValue("key:string:" + key);
}
}
List
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private final RedisTemplate<String, Object> redisTemplate;
// List 저장
public void saveList(String key, String value) {
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
listOperations.rightPush(key, value);
}
// List 인덱스 단일 조회
public String getListValue(String key, long index) {
RedisOperations<String, Object> listOperations = redisTemplate.opsForList().getOperations();
// return (String) listOperations.opsForList().rightPop(key); // 하나의 값을 출력하고 삭제한다.
return (String) listOperations.opsForList().index(key, index);
}
// List 인덱스 범위 조회
public List<Object> getListValues(String key) {
RedisOperations<String, Object> listOperations = redisTemplate.opsForList().getOperations();
return listOperations.opsForList().range(key, 0, -1);
}
}
@Service
@RequiredArgsConstructor
public class Service {
private final RedisRepository redisRepository;
// List 저장
public void saveList(String key, String value) {
redisRepository.saveList("listKey:" + key, "listTest" + value);
}
// List 단일 조회
public String getListValue(String key, long index) {
return redisRepository.getListValue("listKey:" + key, index);
}
// List 전체 조회
public List<Object> getListValues(String key) {
return redisRepository.getListValues("listKey:" + key);
}
}
Set
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private final RedisTemplate<String, Object> redisTemplate;
// Set 저장
public void saveSet(String key, String value) {
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
setOperations.add(key, value);
}
// Set 단일 조회
public Object getSetValue(String key) {
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
// return setOperations.pop(key); // 하나의 값을 출력하고 삭제한다.
return setOperations.randomMember(key); // 랜덤으로 하나의 값을 출력한다.
}
// set 전체 조회
public Set<Object> getSetValues(String key) {
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
// return setOperations.intersect(key); // 집합처럼 다른 키와 합, 교, 차 집합을 구할 수 있음
return setOperations.members(key);
}
}
@Service
@RequiredArgsConstructor
public class Service {
private final RedisRepository redisRepository;
// Set 저장
public void saveSet(String key, String value) {
redisRepository.saveSet("setKey:" + key, "setTest" + value);
}
// Set 단일 조회
public String getSetValue(String key) {
return (String) redisRepository.getSetValue("setKey:" + key);
}
// set 전체 조회
public Set<Object> getSetValues(String key) {
return redisRepository.getSetValues("setKey:" + key);
}
}
Sorted Set
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private final RedisTemplate<String, Object> redisTemplate;
// Sorted Set 저장
public void saveZSet(String key, String value, double score) {
ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add(key, value, score);
}
// Sorted set 인덱스 범위 조회
public Set<Object> getZSetIndexValues(String key) {
ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
return zSetOperations.range(key, 0, -1);
}
// Sorted Set 스코어 조회
public Set<Object> getZSetScoreValues(String key, int min, int max) {
ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
return zSetOperations.rangeByScore(key, min, max);
}
// Sorted Set 스코어 키-벨류 조회
public Set<Object> getZSetScoreKeyValues(String key, int min, int max) {
ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
return Collections.singleton(zSetOperations.rangeByScoreWithScores(key, min, max));
}
}
@Service
@RequiredArgsConstructor
public class Service {
private final RedisRepository redisRepository;
// Sorted Set 저장
public void saveZSet(String key, String value, double score) {
for (int i = 1; i < 4; i++) {
redisRepository.saveZSet("score:" + key, value + i , score * i);
}
}
// Sorted set 인덱스 범위 조회
public Set<Object> getZSetIndexValues(String key) {
return redisRepository.getZSetIndexValues("score:" + key);
}
// Sorted Set 스코어 조회
public Set<Object> getZSetScoreValues(String key, int min, int max) {
return redisRepository.getZSetScoreValues("score:" + key, min, max);
}
// Sorted Set 스코어 조회
public Set<Object> getZSetScoreKeyValues(String key, int min, int max) {
return redisRepository.getZSetScoreKeyValues("score:" + key, min, max);
}
}
Hash
@Repository
@RequiredArgsConstructor
public class RedisRepository {
private final RedisTemplate<String, Object> redisTemplate;
// Hash 저장
public void saveHash(String key, String hashKey, String value) {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
hashOperations.put(key, hashKey, value);
}
// Hash 다중 저장
public void saveHash(String key, Map<String, String> value) {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
hashOperations.putAll(key, value);
}
// Hash 단일 조회
public Object getHash(String key, String hashKey) {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
return hashOperations.get(key, hashKey);
}
// Hash key 전체 조회
public Set<Object> getHashKeys(String key) {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
return hashOperations.keys(key);
}
// Hash value 전체 조회
public List<Object> getHashValues(String key) {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
return hashOperations.values(key);
}
// Hash 전체 조회
public Map<Object, Object> getHashMaps(String key) {
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
return hashOperations.entries(key);
}
}
@Service
@RequiredArgsConstructor
public class Service {
private final RedisRepository redisRepository;
// Hash 저장
public void saveHash(String key, String hashKey, String value) {
redisRepository.saveHash("hashKey:" + key, "testKey:" + hashKey, "hashTest" + value);
}
// Hash 다중 저장
public void saveAllHash(String key, String hashKey, String value) {
Map<String, String> map = new HashMap<>();
map.put("testKey:" + hashKey + "first", value + "first");
map.put("testKey:" + hashKey + "second", value + "second");
map.put("testKey:" + hashKey + "third", value + "third");
redisRepository.saveHash("hashKey:" + key, map);
}
// Hash 단일 조회
public String getHash(String key, String hashKey) {
return (String) redisRepository.getHash("hashKey:" + key, "testKey:" + hashKey);
}
// Hash key 전체 조회
public Set<Object> getHashKeys(String key) {
return redisRepository.getHashKeys("hashKey:" + key);
}
// Hash value 전체 조회
public List<Object> getHashValues(String key) {
return redisRepository.getHashValues("hashKey:" + key);
}
// Hash 전체 조회
public Map<Object, Object> getHashMaps(String key) {
return redisRepository.getHashMaps("hashKey:" + key);
}
}
기본적인 자료구조들로 저장을 하고 간단한 조회 정도는 할 줄 알아야 다양한 곳에 적용시킬 때 활용을 잘할 수 있을 거라 보고 저장과 조회 방법들로 다양하게 사용해 봤다. 사용한 메서드들도 오버로딩된 메서드들도 많고 다르게 조회하는 방법들도 더 있지만 기본적으로 사용할 거 같은 방법으로 사용해봤다.
대부분은 API로 사용을 할 경우가 많을 듯하여 간단하게 컨트롤러로 값을 받아 서비스에서 사용하도록 해 postman을 이용해서 테스트를 해보았다.
처음에는 들어가는 값들에 문제가 있어 오류가 간혹 났지만, 하다 보니 사용하는 방법들이 비슷하여 적응하는 데는 문제가 없는 것 같다.