1 使用jvm的空间换时间
当缓存达到一定程度后,容易引发OOM问题
2.该缓存位于一个jvm 里面
该缓存不能共享
3 缓存的模型对代码的改造太大,不容易扩展
.3.1 引入切面的包
aspectj
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
3.2 定义一个切面类
3.3 切点的切入
大家有会切面表达时的写法
@Around(“execution (* com.sxt.service.impl.MenuServiceImpl.loadAllMenu())”)
3.4 实现环绕通知的逻辑
@Component
@Aspect
public class CacheAspect {
private static Map<String,Object> caches = new HashMap<>();
private static final String ALL_MENU_LABEL = "alll-menu-data";
@Around("execution (* com.sxt.service.impl.MenuServiceImpl.loadAllMenu())")
public Object cache(ProceedingJoinPoint ponit) {
if(caches.containsKey(ALL_MENU_LABEL)) {
System.out.println("缓存里面有");
return caches.get(ALL_MENU_LABEL);
}
Object result = null ;
try {
System.out.println("执行真实方法的调用");
result = ponit.proceed(ponit.getArgs()); // 在此实现了真实方法的调用
// 放入缓存
caches.put(ALL_MENU_LABEL, result);
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
}
缓存的击穿
Select * from t_user where id = -10;
查询的数据一致无法命中缓存(缓存里面一直没有)
那缓存击穿的本质原因是:
有些数据在缓存中没有,在数据库中也没有,这样导致每次访问缓存,都查不到,结果必须落到去查数据库,但是数据库也没有,这样就导致每次一访问这样的数据,都会既查缓存,又查数据库,大大的浪费了时间,还增加了访问压力。
通常可以用这样的方式避免这个问题,如果在数据库中不存在的话,就在缓存中做一个空标志,(比如new 一个新对象,但是这个对象的字段都是空的。)数据库数据实时同步到缓存中,以后对这些数据的访问,直接就能在缓存中查到,就不需再查数据库了,通过查询缓存发现得到的为空的标志,就直接返回。
1 在执行查询之前,如果预先知道数据库里面没有这个值,我可以不查询数据库
2 查询数据库,发现没有该值,现在我在缓存里面缓存一个null 值
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
缓存击穿和缓存雪崩有点类似,区别是缓存击穿针对的是某一个非常热点的key,这个key在某一时刻失效造成所有请求都访问数据库;缓存雪崩是针对一系列缓存同时失效,造成大量请求访问数据库造成雪崩。
缓存击穿也可以使用加锁的方式,让只有一个线程查询数据库写缓存,其他线程等待。
缓存的雪崩
当黑客使用大量的数据测试(不止是-1 ,-1–> 无穷)则缓存里面可能缓存很多null,null 也占用空间,过一个缓存慢了,无法存入新的值了,该现象被称为缓存的雪崩。
解决方案
产生的原因是:数据库里面,没有该值产生的
若实现知道该数据库里面没有该值,这个问题就可以解决。要求不能查数据。
HashSet
什么数据结构不占内存
1 int = 4个字节=48 = 32 bit
1bit 内存占用下来了
图片怎么存储(19801080p)
位图-> 存储图片
借着该图片的存储,我们可以使用BloomFilter