在高并发场景中,为了减少数据库的压力,咱们会引入缓存。java
一个简单的查询操做,以下所示:数据库
伪代码以下:缓存
public Object getObjById(Integer objId){ String key = "Lock:Obj:"+objId; //先从缓存中获取数据 Obj obj= DistributeCacheUtil.get(key); if(obj!=null){ //若是缓存中存在则直接返回缓存中数据 return obj; } //若是缓存中不存在该数据,从数据库中查询 obj= DbUtil.getObjById(objId); if(obj!=null){ //若是 数据库中存在,将查询出来的数据放入缓存,设置过时时间 DistributeCacheUtil.set("Lock:Obj:"+objId,obj,1000); } //返回 return obj; }
但是这里出现一个问题,好比秒杀场景或者一些其余场景,某一时刻开始进行秒杀,这时候大量的请求会请求到后台,若是没有事先进行数据缓存预热,这个时候缓存里是没有数据的,那么大量的请求回去查询数据库,这样整个缓存就失去意义了。并发
如何解决?分布式
1.提早进行数据缓存预热,好比项目启动时,或者定时器,先将数据查询出来放到缓存。高并发
2.加入锁,具体伪代码逻辑以下所示:线程
public Object getObjById(Integer objId){ String key = "Lock:Obj:"+objId; //先从缓存中获取数据 Obj obj= DistributeCacheUtil.get(key); if(obj!=null){ //若是缓存中存在则直接返回缓存中数据 return obj; } //若是缓存中不存在该数据 //加锁,这里分为阻塞锁和非阻塞锁 if(DistributeCacheUtil.tryLock(key)){ //进锁之后先从缓存中获取数据 //若是第一个线程持锁后,加数据加载进缓存后,后来进来的线程能够直接从缓存中拿 obj= DistributeCacheUtil.get(key); if(obj!=null){ //若是缓存中存在则直接返回缓存中数据 return obj; } //若是缓存中仍是不存在,再从数据库中拿 obj= DbUtil.getObjById(objId); if(obj!=null){ //若是数据库中存在,将查询出来的数据放入缓存,设置过时时间 DistributeCacheUtil.set("Lock:Obj:"+objId,obj,1000); } //返回 return obj; }else{ //这里是处理分布式锁为非阻塞锁的状况,若是是阻塞式锁,这里就没必要要处理了 //这里根据实际状况处理,好比直接返回null(秒杀场景,直接返回卖完了) //或者休眠1秒钟,再从缓存中拿 //或者自旋去查询缓存 return null; } }