레디스
NoSQL 중 하나이며 캐쉬서버이다. 나는 refresh token 을 쓰기위해
또는 캐쉬사용을 위해 사용했다.
옛날 소스들이라 조금 지저분할 수도..
-- JPA --
레디스 gradle
// todo: Redis : cache server
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
application.properties
# redis server
redis.host=localhost
redis.port=6379
ServletInitializer
SimpleDmsApplication와 같은 자리에 놓자
package com.example.simpledms;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SimpleDMSApplication.class);
}
}
config 파일
package com.example.simpledms.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
import java.time.Duration;
@Configuration
@Slf4j
@EnableRedisRepositories
public class RedisConfig {
// Redis IP
@Value("${redis.host}")
private String redisHost;
// Redis Port Number
@Value("${redis.port}")
private int redisPort;
// 레디스 연결
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort);
log.info("레디스 연결됨");
return new LettuceConnectionFactory(configuration);
}
// 레디스 관리 : 1) 생성 dept : ttl - 1 minute
// TODO : dept = key값 , ttl = 만료시간
@Bean
public RedisCacheManager cacheManager() {
// Redis 캐시 설정 함수를 호출해서 래디스 설정
RedisCacheConfiguration cacheConfig = myDefaultCacheConfig(Duration.ofMinutes(10))
.disableCachingNullValues(); // 캐싱할 때 null 값을 허용하지 않음
return RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(cacheConfig)
.withCacheConfiguration("dept", myDefaultCacheConfig(Duration.ofMinutes(1))) // dept 캐쉬 생성
// .withCacheConfiguration("customer", myDefaultCacheConfig(Duration.ofMinutes(1))) // customer 캐쉬 생성
.build();
}
// Redis 캐시 설정 함수 : 1) 설정 default config 2) 설정 ttl 3) 설정 serialize
private RedisCacheConfiguration myDefaultCacheConfig(Duration duration) {
return RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(duration) // ttl(만료시간) 설정
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // Value 를 직렬화할 때 사용하는 규칙. Jackson2 를 많이 사용함
}
}
model
@RedisHash의 value 값(redis keyspace)에 특정한 값을 넣어줌으로써 추후 해당 데이터에 대한 key가 생성될 때
prefix를 지정할 수 있으며, @Id 어노테이션을 통해 prefix:구분자 형태(keyspace:@id)로 데이터에 대한 키를 저장하여
각 데이터를 구분할 수 있습니다.
이때, @Id 어노테이션은 org.springframework.data.annotation.Id를 사용하며,
null로 저장될 경우 랜덤 값으로 설정됩니다.
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
@RedisHash(value = "name" , timeToLive = 120) // 120초 생성
public class RedisEntity {
@Id
private String id;
private String key;
@Indexed
private String value;
}
Repository
package com.example.simpledms.repository.basic;
import com.example.simpledms.model.entity.basic.RedisEntity;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface RedisEntityRepository extends CrudRepository<RedisEntity , String> {
}
Service
@Slf4j
@Service
public class RedisEntityService {
@Autowired
RedisEntityRepository redisEntityRepository;
/**
* TODO : 레디스 저장
* @param redisEntity
* @return
*/
public RedisEntity save(RedisEntity redisEntity) {
return redisEntityRepository.save(redisEntity);
}
public Optional<RedisEntity> findById(String id) {
return redisEntityRepository.findById(id);
}
}
Controller
@RestController
@Slf4j
public class RedisEntityConstroller {
@Autowired
RedisEntityService redisEntityService;
@PostMapping("/redis-entity")
public ResponseEntity<Object> save(@RequestBody RedisEntity redisEntity) {
RedisEntity redisEntity1 = redisEntityService.save(redisEntity);
return new ResponseEntity(redisEntity1, HttpStatus.ACCEPTED);
}
@GetMapping("/redis-entity/{id}")
public ResponseEntity<Object> findById(@PathVariable String id) {
Optional<RedisEntity> optionalRedisEntity = redisEntityService.findById(id);
return new ResponseEntity<>(optionalRedisEntity.get(),HttpStatus.ACCEPTED);
}
}
-- 캐쉬 서버 --
여기까지 됬다면 캐쉬서버는 간단하다
처음 어떠한 값을 조회할때는 DB를 통해서 가져오고 (Redis 서버에 들어가기만 함)
그 다음부터는 캐쉬서버를 통하여 빠르게 값을 가져오는 그런 구조
@Cacheable : 조회시 캐싱 저장 : select 시 사용
@CachePut : 무조건 캐시 저장 : update 시 사용
@Cacheevict : 캐시 삭제 : delete 시 사용
참고 문헌
1. Indexed 사용 주의점
https://dkswnkk.tistory.com/709
2. redis 데이터 타입
https://wildeveloperetrain.tistory.com/243
사용해보자
여러 캐쉬중 dept 라는 캐쉬를 사용하였다.
package com.example.simpledms.service.basic;
import com.example.simpledms.model.entity.basic.Dept;
import com.example.simpledms.repository.basic.DeptRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.Optional;
// springboot 프레임워크에 객체를 생성함 : 싱글톤 유형
@Slf4j
@Service
// 레디스 캐싱 기능 활성화
@EnableCaching
public class DeptService {
@Autowired
DeptRepository deptRepostory; // 샘플데이터 DB에 접근하는 객체
@Cacheable("dept")
public Optional<Dept> findById(int dno) {
log.debug("캐쉬 안됨");
Optional<Dept> optionalDept = deptRepostory.findById(dno);
return optionalDept;
}
@CacheEvict("dept")
public boolean removeById(int dno) {
if (deptRepostory.existsById(dno)) {
deptRepostory.deleteById(dno);
return true;
}
return false;
}
}
-- 간단한 RedisTemplate<String , String> --
config 파일
package com.example.redis;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
private String redisHost = "localhost";
private String redisPort = "7880";
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(redisHost);
redisStandaloneConfiguration.setPort(Integer.parseInt(redisPort));
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
System.out.println(lettuceConnectionFactory.toString());
return lettuceConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
Controller
package com.example.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RedisController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@PostMapping("/redisTest")
public ResponseEntity<?> addRedisKey() {
ValueOperations<String, String> vop = redisTemplate.opsForValue();
vop.set("yellow", "banana");
vop.set("red", "apple");
vop.set("green", "watermelon");
return new ResponseEntity<>(HttpStatus.CREATED);
}
@GetMapping("/redisTest/{key}")
public ResponseEntity<?> getRedisKey(@PathVariable String key) {
ValueOperations<String, String> vop = redisTemplate.opsForValue();
String value = vop.get(key);
return new ResponseEntity<>(value, HttpStatus.OK);
}
}
끝이요
'SpringBoot' 카테고리의 다른 글
Sprinboot 3.x버젼 - QueryDSL 설정과 간단하게 사용해보자 (1) | 2023.12.17 |
---|---|
Springboot - Security (1) | 2023.12.14 |
윈도우 카프카 - Kafka 를 Springboot 에서 간단히 써보자 (1) | 2023.12.12 |
MySQL + Springboot JPA + logback (1) | 2023.12.12 |
SpringBoot - MyBatis (RestController) (0) | 2023.10.16 |