SpringBoot에서 Redis에 접근하기 위한 2가지 방법을 제공하는데 RedisTemplate, RedisRepoitory 이다.
이 2가지를 설정하고 테스트를 실행해보면서 SpringBoot에서 Redis 활용방법을 알아본다.
1. SpringBoot Redis 설정
먼저 Redis를 사용하기 위해 의존성 및 빈 설정을 진행한다.
build.gradle에 redis 의존성을 추가한다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
application.yml에 redis 접속정보를 설정한다.
spring:
redis:
host: 127.0.0.1
port: 6379
# password: 'xxxx' # 비밀번호 있을 경우 설정
Redis 빈설정 RedisConfig파일을 작성한다. RedisProperties를 주입받으면 yml에 설정한 redis 설정 항목들을 객체 형태로 가져와서 사용할 수 있다. RedisTemplate은 StringRedisTemplate 등 편의를 위해 제공해주는 템플릿도 있는데 일반RedisTemplate과 비교를 위해 일단 2개 모두를 등록해봤다.
@RequiredArgsConstructor
@Configuration
public class RedisConfig {
private final RedisProperties redisProperties;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
}
/**
java Object를 redis에 저장하는 경우 사용
- StringRedisSerializer를 사용해서 String값에 대한 적용도 가능하나
default는 JdkSerializationRedisSerializer
*/
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
/**
일반적인 String 값을 key, value로 사용하는 경우 사용
*/
@Bean
public StringRedisTemplate stringRedisTemplate(){
StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory());
return stringRedisTemplate;
}
}
먼저 StringRedisTemplate과 RedisTemplate 차이를 테스트 해보면 redis에 저장되는 형식이 차이가 있어 특별한 경우가 아니면 StringRedisTemplate를 사용하면 될 것 같다.
2. RedisTemplate 활용
이제 RedisTemplate으로 몇가지 기능들을 테스트해본다. 테스트 코드는 아래와 같다.
@SpringBootTest
public class RedisTemplateTest {
@Autowired
StringRedisTemplate redisTemplate;
@Test
@DisplayName("String Type 테스트")
public void testStrings() {
final String key = "string_key";
final ValueOperations<String, String> stringValueOperations = redisTemplate.opsForValue();
stringValueOperations.set(key, "1"); // redis set 명령어
final String result_1 = stringValueOperations.get(key); // redis get 명령어
System.out.println("result_1 = " + result_1);
stringValueOperations.increment(key); // redis incr 명령어
final String result_2 = stringValueOperations.get(key);
System.out.println("result_2 = " + result_2);
// redis-cli> get string_key
}
@Test
@DisplayName("List Type 테스트")
public void testList() {
final String key = "list_key";
final ListOperations<String, String> stringListOperations = redisTemplate.opsForList();
stringListOperations.rightPush(key, "H");
stringListOperations.rightPush(key, "e");
stringListOperations.rightPush(key, "l");
stringListOperations.rightPush(key, "l");
stringListOperations.rightPush(key, "o");
stringListOperations.rightPushAll(key, " ", "t", "e", "s", "t");
stringListOperations.set(key, 0, "h"); // 0번째 변경
final String character_1 = stringListOperations.index(key, 1);
System.out.println("index value = " + character_1);
final Long size = stringListOperations.size(key);
System.out.println("list size = " + size); // size
final List<String> resultRange = stringListOperations.range(key, 0, 9);
System.out.println("ResultRange = " + Arrays.toString(resultRange.toArray()));
final List<String> allRange = stringListOperations.range(key, 0, -1);
System.out.println("AllRange = " + Arrays.toString(allRange.toArray()));
stringListOperations.trim(key, 2, 5); // 리스트의 start부터 end만큼 보존하고 나머진 삭제
System.out.println("2~5 Trim Range = " + stringListOperations.range(key, 0, -1));
// redis-cli> lrange list_key 0 -1
}
@Test
@DisplayName("Set Type 테스트")
public void testSet() {
String key = "set_key";
SetOperations<String, String> stringSetOperations = redisTemplate.opsForSet();
stringSetOperations.add(key, "H");
stringSetOperations.add(key, "e");
stringSetOperations.add(key, "l");
stringSetOperations.add(key, "l");
stringSetOperations.add(key, "o");
Set<String> set = stringSetOperations.members(key);
System.out.println("all members = " + Arrays.toString(set.toArray())); // 전체 조회
Long size = stringSetOperations.size(key);
System.out.println("size = " + size); // size
Cursor<String> cursor = stringSetOperations.scan(key, ScanOptions.scanOptions().match("*").count(3).build());
while(cursor.hasNext()) {
System.out.println("cursor = " + cursor.next());
}
// redis-cli> smembers set_key
}
@Test
@DisplayName("SortedSet 테스트")
public void testSortedSet() {
String key = "sortedset_key";
ZSetOperations<String, String> stringZSetOperations = redisTemplate.opsForZSet();
stringZSetOperations.add(key, "o", 20);
stringZSetOperations.add(key, "H", 1);
stringZSetOperations.add(key, "e", 5);
stringZSetOperations.add(key, "l", 10);
stringZSetOperations.add(key, "l", 15);
Set<String> range = stringZSetOperations.range(key, 0, 5);
System.out.println("range = " + Arrays.toString(range.toArray()));
Long size = stringZSetOperations.size(key);
System.out.println("size = " + size);
Set<String> scoreRange = stringZSetOperations.rangeByScore(key, 0, 13);
System.out.println("scoreRange = " + Arrays.toString(scoreRange.toArray()));
// redis-cli> zrange sortedset_key 0 -1
}
@Test
@DisplayName("Hash Type 테스트")
public void testHash() {
String key = "hash_key3";
HashOperations<String, Object, Object> stringObjectHashOperations = redisTemplate.opsForHash();
stringObjectHashOperations.put(key, "Hello", "value1");
stringObjectHashOperations.put(key, "Hello2", "value2");
stringObjectHashOperations.put(key, "Hello3", "value3");
Object hello = stringObjectHashOperations.get(key, "Hello");
System.out.println("hello = " + hello);
Map<Object, Object> entries = stringObjectHashOperations.entries(key);
System.out.println("entries Map = " + entries);
System.out.println("entries = " + entries.get("Hello2"));
Long size = stringObjectHashOperations.size(key);
System.out.println("size = " + size);
// redis-cli> hget hash_key, hkeys hash_key, hvals hash_key
}
}
아래와 같이 Redis 타입별로 RedisTemplate에서 제공되는 메소드가 각각 있어서 redis명령이 가능하다.
3. RedisRepository 활용
RedisRepository를 활용하면 Spring Data JPA처럼 객체를 기반으로 Redis에 객체를 저장하고 조회 할 수 있다.
먼저 RedisConfig에 설정을 추가한다.
@RequiredArgsConstructor
@Configuration
@EnableRedisRepositories // 추가 설정
public class RedisConfig {
private final RedisProperties redisProperties;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
}
@Bean
public StringRedisTemplate stringRedisTemplate(){
StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory());
return stringRedisTemplate;
}
}
다음으로 redis에 저장할 Domain 객체를 선언하다.
@RedisHash 및 @Id 추가하게 되는데 Redis에 저장되는 key는 @RedisHash의 value + @Id가 붙어있는 멤버변수로 되기 때문이다.
@Getter
@RedisHash(value = "member", timeToLive = 100)
public class Member {
@Id
private String id;
private String fName;
private String lName;
private Address address;
@Builder
public Member(String id, String fName, String lName, Address address) {
this.id = id;
this.fName = fName;
this.lName = lName;
this.address = address;
}
}
@Getter
public class Address {
private String address;
public Address(String address) {
this.address = address;
}
}
RedisRepository를 선언한다.
public interface MemberRedisRepository extends CrudRepository<Member, String> {
}
TestCase를 작성하고 돌려본다.
@SpringBootTest
public class RedisRepositoryTest {
@Autowired
private MemberRedisRepository redisRepository;
@Test
@DisplayName("member 저장 및 조회")
public void saveMemberTest() {
Address address = new Address("Korea Seoul");
Member member = new Member(null, "kildong", "hong", address);
// 저장
Member savedPerson = redisRepository.save(member);
// 조회
Optional<Member> findMember = redisRepository.findById(savedPerson.getId());
assertThat(findMember.isPresent()).isEqualTo(Boolean.TRUE);
assertThat(findMember.get().getFName()).isEqualTo(member.getFName());
}
}
마지막으로 redis에서 확인해본다.
key를 조회해보면 "member"는 member의 key들을 가지고 있는 set, "member:xxxxxx"는 각 member의 정보를 가지고 있는 hash 이다.
set타입의 member를 조회해보면 아래와 같다.
마지막으로 hash타입의 member를 조회해보면 아래와 같다.
'개발 > SpringBoot' 카테고리의 다른 글
SpringBoot RabbitMQ 활용(Simple Queue, Pub/Sub) (0) | 2022.12.23 |
---|---|
SpringBoot Redis 활용 - Pub/Sub (0) | 2022.12.16 |
SpringBoot Redis 세션 사용 (0) | 2022.09.06 |
SpringBoot SpringDoc(OpenAPI)을 이용한 Swagger 그룹화, 전역인증&Parameter 설정 (0) | 2022.08.03 |
SpringBoot SpringDoc(OpenAPI)을 이용한 Swagger 적용 (0) | 2022.08.02 |
댓글