Redis无侵入式地缓存业务查询数据
2018-01-18 11:48
309 查看
这里是根据我们自己的业务特点(极少数据更新且不要求数据精确,某些查询的时间又比较长),我们采用了 Redis 做缓存,使用 Hash 数据结构缓存数据。
我们的业务查询都是通过 Service 层整合多个 DAO 完成 DTO 的组装,基于业务特点,没必要将各个 DAO 的数据缓存,而是直接缓存 Service 的最终 DTO 结果。
首先,在 Spring Boot 里实例化 RedisTemplate:
@Configuration
public class RedisConfig {
private static final Logger logger = Logger.getLogger(RedisConfig.class);
@Bean
public RedisConnectionFactory genFactory(){
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName("192.168.1.82");
jedisConnectionFactory.setUsePool(true);
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
logger.info("进入 RedisConfig.redisTemplate() 方法。。。。。。。。。。。。");
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
}当然,pom.xml 文件得加上 Redis 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> 然后,定义一个注解,凡是希望数据被缓存的 Service.get**方法上都加上这个注解:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
/**
* 1. 使用 Redis 的 Hash 缓存 Service 层的查询结果
* 2. Key 使用类名 + 方法名,
* 3. 任一 field 的值使用参数的String字符串连接,如果无参数,就使用默认值
* 4. 希望结果被缓存的get**方法只需要加上自定义的 CurieCache 注解,就会被拦截:
* a. 如果缓存里有就直接从缓存里拿数据
* b. 否则先执行业务查询,最终结果在返回前放入缓存
* @author Allen
*/
@Component
@Aspect
public class RedisAdvice {
private Logger logger = LoggerFactory.getLogger(RedisAdvice.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Around("execution(* com.hebta.curie.service.*Service.get*(..))")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
String key = null;
String field = null;
if (method.isAnnotationPresent(CurieCache.class)){
logger.info("当前方法设置了CurieCache 注解");
String target = pjp.getTarget().toString();
StringBuilder kSb = new StringBuilder();
kSb.append(target.substring(target.lastIndexOf(".") + 1, target.indexOf("@")))
.append(":").append(method.getName());
key = kSb.toString();
logger.info("target is : {}, key is : {}", target, key);
if (pjp.getArgs().length > 0) {
logger.info("方法 {} 无参数", method.getName());
StringBuilder sb = new StringBuilder();
for (Object obj : pjp.getArgs()) {
sb.append(obj.toString());
}
field = sb.toString();
} else {
field = "blank";
}
logger.info("field is : {}", field);
if (redisTemplate.opsForHash().hasKey(key, field)){
logger.info("缓存里有该结果,直接从缓存里取");
return redisTemplate.opsForHash().get(key, field);
} else {
logger.info("没有缓存该结果,先计算,存入缓存,再返回");
Object result = pjp.proceed();
redisTemplate.opsForHash().put(key, field, result);
return result;
}
} else {
logger.info("无 CurieCache 注解");
return pjp.proceed();
}
}
}
我们的业务查询都是通过 Service 层整合多个 DAO 完成 DTO 的组装,基于业务特点,没必要将各个 DAO 的数据缓存,而是直接缓存 Service 的最终 DTO 结果。
首先,在 Spring Boot 里实例化 RedisTemplate:
@Configuration
public class RedisConfig {
private static final Logger logger = Logger.getLogger(RedisConfig.class);
@Bean
public RedisConnectionFactory genFactory(){
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName("192.168.1.82");
jedisConnectionFactory.setUsePool(true);
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
logger.info("进入 RedisConfig.redisTemplate() 方法。。。。。。。。。。。。");
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
}当然,pom.xml 文件得加上 Redis 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> 然后,定义一个注解,凡是希望数据被缓存的 Service.get**方法上都加上这个注解:
@Documented//文档 @Retention(RetentionPolicy.RUNTIME)//在运行时可以获取 @Target(ElementType.METHOD)//作用到类,方法,接口上等 public @interface CurieCache { }比如我们想缓存下面这个查询结果,就直接加上注解:
@CurieCache public CohortDefinitionDTO getCohortProcessSummaryById(Integer defId){ List<ConceptData> datas = new ArrayList<ConceptData>(); ... }最后,让缓存起作用,就看 Around Advice 了,详细解释已经在该类的注释上了:import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
/**
* 1. 使用 Redis 的 Hash 缓存 Service 层的查询结果
* 2. Key 使用类名 + 方法名,
* 3. 任一 field 的值使用参数的String字符串连接,如果无参数,就使用默认值
* 4. 希望结果被缓存的get**方法只需要加上自定义的 CurieCache 注解,就会被拦截:
* a. 如果缓存里有就直接从缓存里拿数据
* b. 否则先执行业务查询,最终结果在返回前放入缓存
* @author Allen
*/
@Component
@Aspect
public class RedisAdvice {
private Logger logger = LoggerFactory.getLogger(RedisAdvice.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Around("execution(* com.hebta.curie.service.*Service.get*(..))")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
String key = null;
String field = null;
if (method.isAnnotationPresent(CurieCache.class)){
logger.info("当前方法设置了CurieCache 注解");
String target = pjp.getTarget().toString();
StringBuilder kSb = new StringBuilder();
kSb.append(target.substring(target.lastIndexOf(".") + 1, target.indexOf("@")))
.append(":").append(method.getName());
key = kSb.toString();
logger.info("target is : {}, key is : {}", target, key);
if (pjp.getArgs().length > 0) {
logger.info("方法 {} 无参数", method.getName());
StringBuilder sb = new StringBuilder();
for (Object obj : pjp.getArgs()) {
sb.append(obj.toString());
}
field = sb.toString();
} else {
field = "blank";
}
logger.info("field is : {}", field);
if (redisTemplate.opsForHash().hasKey(key, field)){
logger.info("缓存里有该结果,直接从缓存里取");
return redisTemplate.opsForHash().get(key, field);
} else {
logger.info("没有缓存该结果,先计算,存入缓存,再返回");
Object result = pjp.proceed();
redisTemplate.opsForHash().put(key, field, result);
return result;
}
} else {
logger.info("无 CurieCache 注解");
return pjp.proceed();
}
}
}
相关文章推荐
- redis服务器缓存数据库查询出来的数据
- spring boot 整合redis对查询数据做缓存( 利用spring的AOP技术)
- 根据从redis缓存的数据查询出来,在从数据库中取出所有的数据,俩个数据进行比较,去掉重复,剩下库中新插入的数据,取出新数据,然后把redis中的缓存数据清空把从数据库中查出来的所有数据放到redis缓存中
- 查询数据过多页面反应慢引入缓存解决方案(Redis、H2)
- spring boot 整合redis对查询数据做缓存( 利用spring的AOP技术)
- 查询数据过多页面反应慢引入缓存解决方案(Redis、H2)
- Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析
- ExtJS 4.2 业务开发(二)数据展示和查询
- Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析
- spring + redis 实现数据的缓存
- 缓存数据redis的配置-
- spring4.0.9结合redis进行数据的缓存
- java中使用ehcache对jdbc查询数据进行缓存
- 缓存一致性和跨服务器查询的数据异构解决方案canal
- memcache与redis lru 一致性hash 缓存雪崩 缓存无底洞 永久数据被踢现象
- 缓存系列之三:redis安装及基本数据类型命令使用
- Redis缓存服务搭建及实现数据读写
- Redis与spring整合缓存的业务场景使用方法一
- [redis] redis连接远程客户端查询数据
- spring + redis 实现数据的缓存