在某些场景下,我们会经常查询某些特定数据,例如用户跳转各种页面都会查询用户具备该页面权限。
这种需求在流量较小的情况下没有什么问题,但如果出现大流量进行各种页面跳转的花,频繁IO对系统性能是有着非常严重的影响的。
由于用户具备的权限变化较少,我们完全可以将数据缓存在内存中,从而减少与磁盘的IO,提高查询效率
注意笔者编码的特殊处理,由于查询时添加了中间件,为了避免redis宕机等情况导致业务查询不能正常走完流程,我们必须使用try catch进行相应捕获处理,以便后续根据情况解决问题。
package com.macro.mall.tiny.component;
import com.macro.mall.tiny.Annotation.CacheException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class RedisCacheAspect {
private static Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);
@Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..)) ")
public void cacheAspect() {
}
@Around("cacheAspect()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
Object result = null;
logger.info("通过缓存优化接口获取数据");
try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
logger.error(throwable.getMessage());
}
return result;
}
}
笔者这里编码思路很简单,先去redis查,若没有再去数据查询,并存储到redis中。
@RequestMapping(value = "listAll", method = RequestMethod.GET)
@ResponseBody
public CommonResult<List<JSON>> getAll() throws Exception {
List<Object> redisPmsBrandList = redisService.lRange("listAll", 0, -1);
List<JSON> resultList = new ArrayList();
if (null != redisPmsBrandList && redisPmsBrandList.size() > 0) {
for (Object cacheValue : redisPmsBrandList) {
JSON json = JSONUtil.parse(cacheValue);
resultList.add(json);
}
return CommonResult.success(resultList);
}
List<PmsBrand> pmsBrands = brandService.ListAll();
for (int i = 0; i < pmsBrands.size(); i++) {
redisService.lPush("listAll", JSONUtil.parse(pmsBrands.get(i)));
}
return CommonResult.success(resultList);
}
我们一味的去捕获问题不是对错误的最佳处理,我们应该对错误进行相应归类若是业务问题导致的错误,我们需要抛出进行处理,而其他非业务的错误我们则可以进行捕获处理。所以为了能够对错误进行分类,我们可以对可能发生业务错误的方法添加一个注解标记一下。
package com.macro.mall.tiny.Annotation;
import java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheException {
}
@Aspect
@Component
public class RedisCacheAspect {
private static Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);
@Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..)) ")
public void cacheAspect() {
}
@Around("cacheAspect()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
Object result = null;
logger.info("通过缓存优化接口获取数据");
try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
if (method.isAnnotationPresent(CacheException.class)) {
logger.error("业务异常,需要排查处理");
} else {
logger.error(throwable.getMessage());
}
}
return result;
}
}