咱們在平常的開發中,常常會遇到查詢數據列表的問題,有些數據是不常常變化的,若是想作一下優化,在提升查詢的速度的同時減輕數據庫的壓力,那麼redis緩存絕對是一個好的解決方案。java
假設有10000個請求,想達到第一次請求從數據庫中獲取,其餘9999個請求從redis中獲取這種效果。git
public List<UsersDO> getAllUserWithNoPage2(){ try{ //序列化器,將key的值設置爲字符串 RedisSerializer redisSerializer=new StringRedisSerializer(); redisTemplate.setKeySerializer(redisSerializer); //查緩存 List<UsersDO> list=(List<UsersDO>)redisTemplate.opsForValue().get("allUsers"); if(null==list){ UsersQuery query=new UsersQuery(); list=usersDOMapper.selectByExample(query); redisTemplate.opsForValue().set("allUsers", list); System.out.println("從數據庫中取數據"); } else{ System.out.println("從緩存中取數據"); } return list; } catch (Exception e) { logger.error("UserService.getAllUserWithNoPage error",e); } return null; }
常規的這種寫法單線程沒有問題,可是考慮到併發的存在,就會出現緩存滲透的問題,也就是不能保證其餘9999個請求都是從redis中取。github
@GetMapping(value = "/test2") public String test2(){ ExecutorService executorService= Executors.newFixedThreadPool(20); for(int i=1 ; i<=10000;i++){ executorService.submit(new Runnable() { @Override public void run() { userService.getAllUserWithNoPage2(); } }); } return "test over"; }
public List<UsersDO> getAllUserWithNoPage(){ try{ //序列化器,將key的值設置爲字符串 RedisSerializer redisSerializer=new StringRedisSerializer(); redisTemplate.setKeySerializer(redisSerializer); //查緩存 List<UsersDO> list=(List<UsersDO>)redisTemplate.opsForValue().get("allUsers"); if(null==list){ //雙重檢測 鎖 synchronized (this) { List<UsersDO> list1 = (List<UsersDO>) redisTemplate.opsForValue().get("allUsers"); if (null == list1) { UsersQuery query=new UsersQuery(); list=usersDOMapper.selectByExample(query); redisTemplate.opsForValue().set("allUsers", list); System.out.println("從數據庫中取數據"); } else{ System.out.println("從緩存中取數據"); } } } else{ System.out.println("從緩存中取數據"); } return list; } catch (Exception e) { logger.error("UserService.getAllUserWithNoPage error",e); } return null; }
@GetMapping(value = "/test") public String test(){ ExecutorService executorService= Executors.newFixedThreadPool(20); for(int i=1 ; i<=10000;i++){ executorService.submit(new Runnable() { @Override public void run() { userService.getAllUserWithNoPage(); } }); } return "test over"; }
壓測結果符合要求。redis
完整代碼已上傳Github :傳送門spring