/**
* @Description: 切面:查询前先查询redis,如果查询不到穿透到数据库,从数据库查询到数据后,保存到redis,然后下次查询可直接命中缓存
*/
@Component
@Aspect
public class RedisAspect {
@Autowired
@Qualifier("redisCache")
private RedisCache redisCache;
//设置切点:使用xml,在xml中配置
@Pointcut("execution(* com.club.common.redis.service.TestService.get(Java.lang.Integer)) and args(applId)") //测试用,这里还额外指定了方法名称,方法参数类型,方法形参等,比较完整的切点表达式
public void myPointCut(){
}
@Around("myPointCut()")
public Object around(ProceedingJoinPoint joinPoint){
//前置:到redis中查询缓存
System.out.println("调用从redis中查询的方法...");
//先获取目标方法参数
String applId = null;
Object[] args = joinPoint.getArgs();
if (args != null && args.length > 0) {
applId = String.valueOf(args[0]);
}
//redis中key格式: applId
String redisKey = applId;
//获取从redis中查询到的对象
Object objectFromRedis = redisCache.getDataFromRedis(redisKey);
//如果查询到了
if(null != objectFromRedis){
System.out.println("从redis中查询到了数据...不需要查询数据库");
return objectFromRedis;
}
System.out.println("没有从redis中查到数据...");
//没有查到,那么查询数据库
Object object = null;
try {
object = joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("从数据库中查询的数据...");
//后置:将数据库中查询的数据放到redis中
System.out.println("调用把数据库查询的数据存储到redis中的方法...");
redisCache.setDataToRedis(redisKey, object);
//将查询到的数据返回
return object;
}
}
从redis中查询数据,以及将数据库查询的数据保存到redis的方法:
/** * * @Description:Redis缓存 */ public class RedisCache { @Resource private JedisPool jedisPool; public JedisPool getJedisPool() { return jedisPool; } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } //从redis缓存中查询,反序列化 public Object getDataFromRedis(String redisKey){ //查询 Jedis jedis = jedisPool.getResource(); byte[] result = jedis.get(redisKey.getBytes()); //如果查询没有为空 if(null == result){ return null; } //查询到了,反序列化 return SerializeUtil.unSerialize(result); } //将数据库中查询到的数据放入redis public void setDataToRedis(String redisKey, Object obj){ //序列化 byte[] bytes = SerializeUtil.serialize(obj); //存入redis Jedis jedis = jedisPool.getResource(); String success = jedis.set(redisKey.getBytes(), bytes); if("OK".equals(success)){ System.out.println("数据成功保存到redis..."); } } }
测试1:此时redis中没有查询对象的数据
结果是:先到redis中查询,没有查到数据,然后代理执行从数据库中查询,然后把数据存入到redis中一份,那么下次查询就可以直接从redis中查询了
测试2:此时redis中已经有上一次从数据库中查询的数据了
在项目中测试后:效果还是非常明显的,有一个超级复杂的查询,格式化之后的sql是688行,每次刷新页面都需要重新查询,耗时10秒左右。
在第一次查询放到redis之后,从redis中查询能够在2秒内得到结果,速度非常快。
上面的是在项目改造前写的一个Demo,实际项目复杂的多,切点表达式是有两三个一起组成的,也着重研究了一下切点表达式的写法
如: