PHP缓存穿透和使用Redis的缓存加锁当你想获取对应的数据时,如果缓存中不存在该KEY,就会去查数据库。如何解决?无论是否为空,都将每次查询的结果放入缓存。公共函数getArticles($key){$expire=60*3;$data=Cache::get($key);//注意:这里使用is_null而不是直接使用(!$data)判断。//使用(!$data)判断的缺点是:如果$data的值为空字符串或者空数组,这里不成立,会继续执行查询DB的语句,造成缓存穿透如果(!is_null($data)){返回$data;$data=$this->searchDB();缓存::放($key,$data,$expire);return$data;}这样做的原因是即使当前查询的key是空字符串或者空数组,结果也会被缓存。下次访问时直接返回,不会造成缓存穿透。2.缓存锁(Redis)如果系统的并发度很高,当缓存过期后,大量的请求会穿透缓存,同时在DB中查询,那我们是否可以设置缓存只请求一旦在数据库中并在缓存过期时缓存它?是的,我们可以使用redis的setNx()setNx($key)类似于set($key),setNx表示setNotExists。$key不存在则设置,存在则不执行任何操作。设置成功返回1,表示当前请求已经获取到当前操作权限,设置失败返回0,表示该资源已经被其他请求获取。如果用代码实现的话,思路是这样的:给缓存中存放的数据添加一个过期时间字段,暂时将这个字段命名为$data['expire'](这个过期时间应该比实际的缓存过期时间短),方便在缓存过期前进行锁和缓存更新。如果$data['expire']到达过期时间,则执行加锁和缓存更新。这时候如果有其他请求进来,就会返回更新前的数据。代码如下:publicfunctiongetArticlesLock($key){$time=time();$过期=10*2;$lockKey='锁:k';$data=Cache::get($key);if(!is_null($data)){//缓存没有过期if($data['expire']>time()){return$data['data'];}//如果加锁失败,说明已经有请求执行加锁,返回Previous缓存数据if(!Redis::setnx($lockKey,1)){return$data['data'];}}睡眠(3);$datat=$this->searchDB();$data=['data'=>$datat,'expire'=>$time+$expire-10];$r=Cache::put($key,$data,$expire);//解锁Redis::del($lockKey);return$data['data'];}当然这里也可以用set()代替setnx()来加锁,用lua脚本来解锁。
