SpringBoot redis 분포 식 캐 시 구현 프로 세 스 분석
응용 시스템 은 캐 시 를 통 해 자주 바 뀌 지 않 는 데 이 터 를 캐 시 하여 시스템 성능 을 향상 시 키 고 시스템 스루풋 을 증가 시 켜 데이터 베이스 등 저속 저장 시스템 에 직접 접근 하지 않도록 해 야 한다.캐 시 된 데 이 터 는 보통 접근 속도 가 빠 른 메모리 나 저 지연 액세스 메모리,서버 에 저 장 됩 니 다.시스템 캐 시 를 사용 합 니 다.보통 다음 과 같은 역할 을 합 니 다.캐 시 웹 시스템 의 출력,예 를 들 어 위 정적 페이지 등 입 니 다.사용자 권한,사전 데이터,설정 정보 등 캐 시 시스템 의 자주 바 뀌 지 않 는 업무 데이터
springBoot 프로젝트 는 모두 마이크로 서비스 배치,A 서비스 와 B 서 비 스 를 분리 하여 배치 하 는 것 을 잘 알 고 있 습 니 다.그러면 그들 은 공유 모듈 의 캐 시 데 이 터 를 업데이트 하거나 가 져 오 거나 A 서비스 에 분포 식 클 러 스 터 를 부하 하 는 방법,A 서비스의 모든 클 러 스 터 가 공공 모듈 의 캐 시 데 이 터 를 동기 화 할 수 있 도록 하 는 방법 은 분포 식 시스템 캐 시 실현 과 관련 됩 니 다.(ehcache 는 Terracotta 구성 요 소 를 통 해 캐 시 클 러 스 터 를 만 들 수 있 습 니 다.이것 은 잠시 말 하지 않 습 니 다)
그러나 ehcache 의 디자인 은 분포 식 캐 시 에 적합 하지 않 기 때문에 오늘 은 redis 로 분포 식 캐 시 를 실현 합 니 다.
구성 도:
1,2 급 캐 시 서버
Redis 캐 시 를 사용 합 니 다.네트워크 접근 을 통 해 메모리 에서 가 져 오 는 것 보다 성능 이 좋 지 않 기 때문에 보통 2 급 캐 시 라 고 부 릅 니 다.메모리 에서 가 져 온 캐 시 데 이 터 를 1 급 캐 시 라 고 부 릅 니 다.응용 시스템 이 캐 시 를 조회 해 야 할 때 먼저 1 급 캐 시 에서 찾 고 있 으 면 되 돌아 갑 니 다.찾 지 못 하면 2 급 캐 시 를 조회 합 니 다.구조 도 는 다음 과 같 습 니 다.
Spring Boot 2 는 앞의 두 가지 캐 시 실현 방식 을 가지 고 있 습 니 다.본 고 는 세 번 째,고속 1,2 급 캐 시 를 간단하게 실현 할 것 입 니 다.
Redis 분산 캐 시
redis 를 도입 한 starter
Redis 설정
application.yml 에 redis 정 보 를 설정 합 니 다.
spring:
redis:
database: 0
host: 192.168.0.146
port: 6379
timeout: 5000
기타 관련 설정
# Redis ( 0)
spring.redis.database=0
# Redis
spring.redis.host=127.0.0.1
# Redis
spring.redis.port=6379
# Redis ( )
spring.redis.password=
# ( )
spring.redis.pool.max-active=8
# ( )
spring.redis.pool.max-wait=-1
#
spring.redis.pool.max-idle=8
#
spring.redis.pool.min-idle=0
# ( )
spring.redis.timeout=0
Redis 캐 시 직렬 화 메커니즘 설정어떤 때 는 대상 을 redis(예 를 들 어 자바 빈 대상)에 저장 해 야 하지만 대상 이 Serializable 이 아니라면 자바 빈 대상 이 Serializable 인 터 페 이 스 를 실현 하도록 해 야 합 니 다.
public class UserPO implements Serializable {
자바 빈 에 게 만 Serializable 인 터 페 이 스 를 실현 시 키 는 것 도 저장 할 수 있 지만 예 쁘 지 않다 면 자바 빈 을 JSon 스타일 로 만들어 redis 에 넣 을 수 있 을 까?직접적인 방식 은 스스로 전환 하 는 것 이지 만 좀 번 거 로 울 수 밖 에 없다.그러면 RedisTemplate 의 직렬 화 체 제 를 수정 할 수 밖 에 없다.설정 류 에서 직렬 화 하 는 방법 을 설정 하면 된다.
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// json
template.setValueSerializer(jacksonSeial);
// StringRedisSerializer redis key
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
사용자 정의 CacheManager
/**
* Redis
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
RedisConfig 전체 코드
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
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.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.net.UnknownHostException;
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* Redis
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
/**
* retemplate ( )
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate();
//
template.setConnectionFactory(factory);
// Jackson2JsonRedisSerializer redis value ( JDK )
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// ,field,get set, ,ANY private public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// , final ,final , String,Integer
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// json
template.setValueSerializer(jacksonSeial);
// StringRedisSerializer redis key
template.setKeySerializer(new StringRedisSerializer());
// hash key value
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
/**
* key
* @return
*/
@Bean
public KeyGenerator myKeyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
Redi 캐 시 주석 사용 하기service:
@CachePut(value = "user",key = "'user_'+#result.id")
public UserPO save(UserPO po) {
userJpaMapper.save(po);
return po;
}
@CachePut(value = "user",key = "'user_'+#result.id")
public UserPO update(UserPO po) {
System.out.println(" ");
userMapper.update(po);
return po;
}
@Cacheable(value = "user", key = "'user_'+#id")
public UserPO getUser(Integer id){
System.out.println(" :"+id);
return userJpaMapper.getOne(id);
}
@CacheEvict(value = "user", key = "'user_'+#id")
public void delete(Integer id) {
userJpaMapper.deleteById(id);
}
테스트 클래스:
@Test
void contextLoads() {
Integer id = 2;
UserPO user1 = userService.getUser(id);
System.out.println(" :"+user1.getUserName());
UserPO user2 = userService.getUser(id);
System.out.println(" :"+user2.getUserName());
}
테스트 결과:첫 번 째 조회 때 데이터 베 이 스 를 방 문 했 고 두 번 째 조회 때 데이터 베 이 스 를 방문 하지 않 았 습 니 다.redis-cli 를 통 해 데이터 가 redis 에 저 장 된 것 을 볼 수 있 습 니 다.
테스트 클래스:
@Test
void updataUser() {
Integer id = 4;
UserPO user1 = userService.getUser(id);
System.out.println(" :"+user1.getUserName()+", :"+user1.getAge());
user1.setAge(60);
userService.update(user1);
UserPO user2 = userService.getUser(id);
System.out.println(" :"+user2.getUserName()+", :"+user2.getAge());
}
테스트 결과:Redis 도구 클래스(redisUtil.java)
1.RedisConfig 에서 redisTemplate 작업 대상 정의
/**
* hash
* @param redisTemplate
* @return
*/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
/**
* redis
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}
/**
*
* @param redisTemplate
* @return
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
/**
*
* @param redisTemplate
* @return
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
/**
*
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
2.redisUtil 도구 류 에서 이 대상 을 사용 하고 조작 방법 을 구축한다.
package com.meng.demo.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* redis
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ValueOperations<String, Object> valueOperations;
@Autowired
private HashOperations<String, String, Object> hashOperations;
@Autowired
private ListOperations<String, Object> listOperations;
@Autowired
private SetOperations<String, Object> setOperations;
@Autowired
private ZSetOperations<String, Object> zSetOperations;
/**============================= ============================*/
/**
*
* @param key
* @param time ( )
* @return
*/
public boolean expire(String key,long time){
try {
if(time>0){
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* key
* @param key null
* @return ( ) 0
*/
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
/**
* key
* @param key
* @return true- 、false-
*/
public boolean hasKey(String key){
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param key
*/
public void del(String ... key){
if(key!=null&&key.length>0){
if(key.length==1){
redisTemplate.delete(key[0]);
}else{
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**============================ValueOperations =============================*/
/**
*
* @param key
* @param value
* @return true- 、 false-
*/
public boolean set(String key,Object value) {
try {
valueOperations.set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param key
* @param value
* @param expireTime ( ) expireTime 0 expireTime 0
* @return true false
*/
public boolean set(String key,Object value,long expireTime){
try {
if(expireTime > 0){
valueOperations.set(key, value, expireTime, TimeUnit.SECONDS);
}else{
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param key
* @return
*/
public Object get(String key){
return key==null ? null:valueOperations.get(key);
}
/**
*
* @param key
* @return
*/
public long incr(String key, long delta){
if(delta<0){
throw new RuntimeException(" 0");
}
return valueOperations.increment(key, delta);
}
/**
*
* @param key
* @param delta ( 0)
* @return
*/
public long decr(String key, long delta){
if(delta<0){
throw new RuntimeException(" 0");
}
return valueOperations.increment(key, -delta);
}
/**================================HashOperations =================================*/
/**
* HashGet
* @param key null
* @param item null
* @return
*/
public Object hget(String key,String item){
return hashOperations.get(key, item);
}
/**
* hashKey
* @param key
* @return
*/
public Map<String, Object> hmget(String key){
return hashOperations.entries(key);
}
/**
* HashSet
* @param key
* @param map
* @return true false
*/
public boolean hmset(String key, Map<String,Object> map){
try {
hashOperations.putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet
* @param key
* @param map
* @param time ( )
* @return true false
*/
public boolean hmset(String key, Map<String,Object> map, long time){
try {
hashOperations.putAll(key, map);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* hash ,
* @param key
* @param item
* @param value
* @return true false
*/
public boolean hset(String key,String item,Object value) {
try {
hashOperations.put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* hash ,
* @param key
* @param item
* @param value
* @param time ( ) : hash ,
* @return true false
*/
public boolean hset(String key,String item,Object value,long time) {
try {
hashOperations.put(key, item, value);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* hash
* @param key null
* @param item null
*/
public void hdel(String key, Object... item){
hashOperations.delete(key,item);
}
/**
* hash
* @param key null
* @param item null
* @return true false
*/
public boolean hHasKey(String key, String item){
return hashOperations.hasKey(key, item);
}
/**
* hash ,
* @param key
* @param item
* @param by ( 0)
* @return
*/
public double hincr(String key, String item,double by){
return hashOperations.increment(key, item, by);
}
/**
* hash
* @param key
* @param item
* @param by ( 0)
* @return
*/
public double hdecr(String key, String item,double by){
return hashOperations.increment(key, item,-by);
}
/**============================set=============================
/**
* key Set
* @param key
* @return
*/
public Set<Object> sGet(String key){
try {
return setOperations.members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* value set ,
* @param key
* @param value
* @return true false
*/
public boolean sHasKey(String key,Object value){
try {
return setOperations.isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* set
* @param key
* @param values
* @return
*/
public long sSet(String key, Object...values) {
try {
return setOperations.add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* set
* @param key
* @param time ( )
* @param values
* @return
*/
public long sSetAndTime(String key,long time,Object...values) {
try {
Long count = setOperations.add(key, values);
if(time>0){
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* set
* @param key
* @return
*/
public long sGetSetSize(String key){
try {
return setOperations.size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* value
* @param key
* @param values
* @return
*/
public long setRemove(String key, Object ...values) {
try {
Long count = setOperations.remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**===============================ListOperations=================================
/**
* list
* @param key
* @param start
* @param end 0 -1
* @return
*/
public List<Object> lGet(String key, long start, long end){
try {
return listOperations.range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* list
* @param key
* @return
*/
public List<Object> lGetAll(String key){
return lGet(key,0,-1);
}
/**
* list
* @param key
* @return
*/
public long lGetListSize(String key){
try {
return listOperations.size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* list
* @param key
* @param index index>=0 , 0 ,1 , ;index<0 ,-1, ,-2 ,
* @return
*/
public Object lGetIndex(String key,long index){
try {
return listOperations.index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* list
* @param key
* @param value
* @return
*/
public boolean lSet(String key, Object value) {
try {
listOperations.rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* list
* @param key
* @param value
* @param time ( )
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
listOperations.rightPush(key, value);
if (time > 0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* list
* @param key
* @param value
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
listOperations.rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* list
* @param key
* @param value
* @param time ( )
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
listOperations.rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* list
* @param key
* @param index
* @param value
* @return
*/
public boolean lUpdateIndex(String key, long index,Object value) {
try {
listOperations.set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* N value
* @param key
* @param count
* @param value
* @return
*/
public long lRemove(String key,long count,Object value) {
try {
Long remove = listOperations.remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
3.테스트
@Test
void test01(){
redisUtil.set("meng","yang");
Object key = redisUtil.get("meng");
System.out.println(key);
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.