Redis Client란 Redis서버와 통신하도록 설계된 라이브러리나 도구
여기서 Jedis와 Lettuce는 자바에서 Redis서버와 통신하기 위한 Redis 클라이언트 라이브러리
원래 Jedis 를 많이 사용했으나 여러 가지 단점 (멀티 쓰레드 불안정, Pool 한계 등등..) 과 Lettuce 의 장점 (Netty 기반이라 비동기 지원 가능) 때문에 Lettuce 로 추세가 넘어감
redis 공통적인 세팅이 있음
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
spring.redis.host=127.0.0.1
spring.redis.port=6379
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
}
Redisrepository RedisTemplate CacheManager
RedisTemplate과 RedisRepository는 Spring Data Redis 프로젝트에서 제공되는 라이브러리/인터페이스로, Redis와의 CRUD 작업을 수행할 수 있습니다. 이들을 사용하면 캐싱 기능을 수동으로 구현하는 것도 가능합니다.
CacheManager는 Spring의 캐싱 추상화를 위한 인터페이스로, 이를 통해 캐싱 동작을 자동화할 수 있습니다.
RedisRepository 사용방법
@RedisHash(value="person")
public class Person {
@Id
private String id;
private String name;
@Indexed
private String token;
@TimeToLive
private long ttl;
}
@RedisHash : value값은 keyspace가 되고 timeToLive를 추가하면 만료시간을 초단위로 설정가능(만료시간 X :-1L)
@Id : 키 값이 됨
-> keyspace : {Id} 로 최종키로 저장됨
-> null이면 랜덤값이 설정됨
@Indexed : 값으로 검색을 할 시에 추가한다
-> Redis의 보조 인덱스를 생성하는 데 사용
-> RDBMS에서 인덱스는 특정 열의 값을 기반으로 빠르게 데이터를 검색하기 위해 사용
-> @Indexed 어노테이션이 붙은 필드는 Redis에 저장될 때 해당 필드를 기반으로 보조 인덱스가 생성
->다만, 인덱스를 추가하는 것은 저장 공간과 데이터를 추가/수정할 때의 추가 작업을 필요로 하기 때문에, 실제로 해당 필드로 검색 작업이 자주 일어나는 경우에만 @Indexed를 사용
@TimeToLive : 따라 필드를 만들어 만료시간을 설정할 수 있음
@Id 또는 @Indexed어노테이션을 적용한 프로퍼티들만 CrudRepository가 제공하는 findBy~ 구문 사용가능
public interface PersonRedisRepository extends CrudRepository<Person, String> {
Optional<RefreshToken> findByToken(String token);
Optional<RefreshToken> findById(String Id);
}
@SpringBootTest
public class RedisRepositoryTest {
@Autowired
private PersonRedisRepository repo;
@Test
void test() {
Person person = new Person("Park", 20,"avscd",10000);
// 저장
repo.save(person);
// `keyspace:id` 값을 가져옴
repo.findById(person.getId());
// Person Entity 의 @RedisHash 에 정의되어 있는 keyspace (people) 에 속한 키의 갯수를 구함
repo.count();
// 삭제
repo.delete(person);
}
}
RedisTemplate 사용방법
여러 다양한 데이터 구조를 제공
cf) RedisRepository와 같이 Spring Data Redis에서 제공하는 Repository 추상화는 기본적으로 Redis의 해시(Hash) 구조를 사용하여 Java 객체를 저장
//RedisConfiguration에 Bean추가
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
@SpringBootTest
public class RedisTemplateTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Test
void testStrings() {
// given
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
String key = "stringKey";
// when
valueOperations.set(key, "hello");
// then
String value = valueOperations.get(key);
assertThat(value).isEqualTo("hello");
}
@Test
void testSet() {
// given
SetOperations<String, String> setOperations = redisTemplate.opsForSet();
String key = "setKey";
// when
setOperations.add(key, "h", "e", "l", "l", "o");
// then
Set<String> members = setOperations.members(key);
Long size = setOperations.size(key);
assertThat(members).containsOnly("h", "e", "l", "o");
assertThat(size).isEqualTo(4);
}
@Test
void testHash() {
// given
HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();
String key = "hashKey";
// when
//hashOperations.put(key, "field1", "value1");
hashOperations.put(key, "hello", "world");
// then
Object value = hashOperations.get(key, "hello");
assertThat(value).isEqualTo("world");
Map<Object, Object> entries = hashOperations.entries(key);
assertThat(entries.keySet()).containsExactly("hello");
assertThat(entries.values()).containsExactly("world");
Long size = hashOperations.size(key);
assertThat(size).isEqualTo(entries.size());
}
}
Redis에서 key는 데이터 베이스내에서 각 해시값이고 그 내부의 set,string혹은 map으로 되어있는 것
Redis의 문자열 (String) 데이터 타입과 관련된 연산을 위한 메서드입니다.
예: set, get, increment 등의 기본 값 연산을 수행합니다.
Redis의 리스트 (List) 데이터 타입과 관련된 연산을 수행합니다.
예: leftPush, rightPush, range 등의 리스트 연산을 수행합니다.
Redis의 세트 (Set) 데이터 타입과 관련된 연산을 수행합니다.
예: add, remove, isMember 등의 세트 연산을 수행합니다.
Redis의 정렬된 세트 (Sorted Set, ZSet) 데이터 타입과 관련된 연산을 수행합니다.
예: add, rangeByScore, remove 등의 정렬된 세트 연산을 수행합니다.
Redis의 해시 (Hash) 데이터 타입과 관련된 연산을 수행합니다.
예: put, get, entries 등의 해시 연산을 수행합니다.
CacheManger 사용방법
//RedisConfig에 빈추가
@Bean
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
RedisCacheConfiguration con=RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(con)
.build();
}
@Cacheable(key = "#personId",value = CacheKey.KEY_PERSON)
public PersonCache getPerson{(String personId){
.....
}
@Cacheable
캐시에 데이터있으면 메소드 실행하지 않고 값을 가져오고 캐시에 데이터가 없으면 메소드 실행하여 값을 저장
캐시를 가져오는 메소드에 붙이는 어노테이션
key
실제로 캐시 내에서 항목을 구분하는 키를 생성하는 방법을 나타냄
value (또는 cacheNames)
어느 캐시 영역에 해당 항목이 저장되어야 하는지를 나타냄
condition
메서드 결과가 캐시에 저장되기 전에 조건을 확인하는 SpEL 표현식입니다. 표현식의 결과가 true일 때만 캐싱이 수행됩니다.
예: @Cacheable(value="books", condition="#name.length() < 32")
unless
메서드 결과를 캐시에 저장하지 않아야 할 경우를 지정하는 SpEL 표현식입니다. 표현식의 결과가 true일 때, 캐싱이 수행되지 않습니다.
예: @Cacheable(value="books", unless="#result.hardback")
sync
여러 스레드에서 동시에 같은 키의 데이터를 캐시에 저장하는 것을 방지하기 위한 설정입니다. true로 설정하면, 동시에 캐시 미스가 발생한 경우 하나의 스레드만 실제 메서드를 호출하고 결과를 캐시합니다.
예: @Cacheable(value="books", sync=true)
cacheManager
사용할 CacheManager의 빈 이름을 지정합니다. 여러 개의 CacheManager가 있는 경우에 유용합니다.
@CachePut
CacheKey.KEY_PERSON와 같이 해당 캐시 영역의 key에 대한 값을 수정할때
캐시에 기존 값이 있더라도, 그 값을 조회하지 않고, 단순히 새로운 결과로 그 값을 덮어씀
condition
메서드 결과가 캐시에 저장되기 전에 조건을 확인하는 SpEL 표현식입니다. 표현식의 결과가 true일 때만 캐싱이 수행됩니다.
예: @CachePut(value="books", condition="#book.pageCount > 100")
unless
메서드 결과를 캐시에 저장하지 않아야 할 경우를 지정하는 SpEL 표현식입니다. 표현식의 결과가 true일 때, 캐싱이 수행되지 않습니다.
예: @CachePut(value="books", unless="#result.hardback")
cacheManager
사용할 CacheManager의 빈 이름을 지정합니다. 여러 개의 CacheManager가 있는 경우에 유용합니다.
cacheResolver
대상 캐시를 결정하는 CacheResolver의 빈 이름을 지정합니다. cacheNames 또는 value 대신에 사용될 수 있습니다.
keyGenerator
사용할 KeyGenerator의 빈 이름을 지정합니다. key 속성과 함께 사용할 수 없습니다.
@CachePut는 메서드가 호출될 때마다 실행되므로, sync 속성과 같은 캐시 동기화에 관한 설정은 포함되지 않습니다