Java項目中使用Redis緩存案例


   緩存的目的是為了提高系統的性能,緩存中的數據主要有兩種: 

                1.熱點數據。我們將經常訪問到的數據放在緩存中,降低數據庫I/O,同時因為緩存的數據的高速查詢,加快整個系統的響應速度,也在一定程度上提高並發量。

                2.查詢耗時的數據。如果有一些數據查詢十分耗時,那么每次請求這些數據時,都去數據庫查詢的話,會使得系統響應速度特別低,數據庫cpu 100%。將這些數據放緩存,會極大提高系統響應速度,但同時數據實時性較差。

  最近工作中有碰到需要使用緩存的情況,場景如下:app端看板統計數據匯總,在打開app時加載看板數據,匯總數據來源於不同的庫,各個數據的生成接口已經寫好,只需要去調用接口整合數據返回即可。

  具體我們來看看是怎么實現的吧。

 

 第一步,取mysql中查詢各個接口的信息:

 getPanelInfo.java

1 /* service代碼略*/
2 List<PanelDto> panels = panelService.getAllPanels();   //得到接口的名稱,接口的url

 

第二步,根據拿到的信息生成請求參數:

 getPanelInfo.java

 1   WrapResponseModel resonseModel = new WrapResponseModel();
 2   Map<String, String> headers = new HashMap<>();
 3   headers.put("username", username);
 4   headers.put("token",token);
 5   List<String> content = new ArrayList<String>();
 6   for(PanelDto panelDto:panel){
 7   //發送http請求
 8        content.add(HttpRequestUtils.get(panelDto.getUrl(), headers));
 9 }
10 // 返回格式
11   responseModel.setCode(SUCCESS_CODE);
12   responseModel.setData(content);

第三步,發送http請求調用接口:

HttpRequestUtils.java

 1 public static String get(String url, Map<String, String> headers) {
 2         RequestConfig config = RequestConfig.custom().setConnectTimeout(TIME_OUT).setConnectionRequestTimeout(TIME_OUT).setSocketTimeout(TIME_OUT).build();
 3         String ret = null;
 4         //創建HttpClient對象
 5         CloseableHttpClient closeHttpClient = HttpClients.createDefault();
 6         CloseableHttpResponse httpResponse = null;
 7         //發送get請求
 8         HttpGet httpGet = new HttpGet(url);
 9         try {
10             // add header
11             if (Objects.nonNull(headers)) {
12                 Set<String> keys = headers.keySet();
13                 for (Iterator<String> i = keys.iterator(); i.hasNext(); ) {
14                     String key = i.next();
15                     httpGet.addHeader(key, headers.get(key));
16                 }
17             }
18 
19             httpGet.setConfig(config);
20             //執行Get請求 得到Response對象
21             httpResponse = closeHttpClient.execute(httpGet);
22             //httpResponse.getStatusLine() 響應頭信息
23             int httpResponseCode = httpResponse.getStatusLine().getStatusCode();
24 
25             if (200 != httpResponseCode) {
26                 logger.error("http返回值異常, httpResponseCode = " + httpResponseCode);
27             }
28 
29             //返回對象
30             HttpEntity httpEntity = httpResponse.getEntity();
31             ret = EntityUtils.toString(httpEntity, "UTF-8");
32         } catch (UnsupportedEncodingException e) {
33             logger.error(e.getMessage(), e);
34         } catch (ClientProtocolException e) {
35             logger.error(e.getMessage(), e);
36         } catch (IOException e) {
37             //logger.error(e.getMessage(), e);
38         } finally {
39             if (httpResponse != null) {
40                 try {
41                     httpResponse.close();
42                 } catch (IOException e) {
43                     logger.error(e.getMessage(), e);
44                 }
45             }
46             if (closeHttpClient != null) {
47                 try {
48                     closeHttpClient.close();
49                 } catch (IOException e) {
50                     logger.error(e.getMessage(), e);
51                 }
52             }
53         }
54         return ret;
55     }

第四步,查詢數據set進redis,之后返回查詢的數據:

 getPanelInfo.java

1  if (!Objects.equals(redisCache, "false")) {
2 //redisttl過期時間
3 redisProxyHandler.set(redisKey, JSON.toJSONString(responseModel), REDIS_TTL); 4 logger.error("set succeed!!!!!!!!!!!!!!!!"); 5 }

 redisHandler.java

1   public void set(String key, String value, int seconds) {
2             redisCacheProvider.set(key, value, seconds);
3     }

 redisProvider.java

 1     @Autowired
 2     private JedisPool jedisPool;
 3 
 4     public Jedis getJedis() {
 5         Jedis jedis = this.jedisPool.getResource();
 6         // 使用index為2的database
 7         jedis.select(2);
 8         return jedis;
 9     }
10 
11     public void set(String key, String value, int seconds) {
12         Jedis jedis = null;
13         try {
14             jedis = getJedis();
15             jedis.setex(key, seconds, value);
16             Long exp = jedis.ttl(key);
17             if (exp < 0) {
18                 throw new RuntimeException("data time out!");19             }
20         } catch (Throwable e) {
21             logger.error(e.getMessage(), e);
22             throw new TokenException(e.getMessage());
23         } finally {
24             if(jedis != null){jedis.close;}
25         }
26     }

第五步,請求接口的時候,先請求redis緩存,如果命中則返回命中數據,否則,將執行上面的發送http請求在拼湊數據返回的代碼:

getPanelInfo.java

1                 String panelInfo = redisProxyHandler.get(redisKey);
2                 Long expire = redisProxyHandler.getExpire(redisKey);
3                //命中才返回,否則會去發http請求
4                 if (Objects.nonNull(panelInfo) && (expire > 0) && expire <REDIS_TTL) {
5 responseModel = JSON.parseObject(panelInfo, WrapResponseModel.class);
6 return responseModel;
7 }

redisHandler.java

1    public String get(String key) 
2             return redisCacheProvider.get(key);
3    }

redisProvider.java

 1       public String get(String key) {
 2         String value = null;
 3         Jedis jedis = null;
 4         try {
 5             jedis = getJedis();
 6             value = jedis.get(key);
 7         } catch (Throwable e) {
 8             logger.error(e.getMessage(), e);
 9             throw new TokenException(e.getMessage());
10         } finally {
11             if(jedis != null){
12                 jedis.close();
13            }
14         }
15         return value;
16     }

 redis相關配置文件如下

applicationContext.xml

 1  <!-- 讀取配置文件信息 -->
 2     <context:property-placeholder location="classpath:redis.properties" file-encoding="UTF-8" ignore-unresolvable="true"/>
 3 
 4     <!-- Jedis 連接池配置 -->
 5     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
 6         <property name="maxTotal" value="${redis.pool.maxTotal}"/>
 7         <property name="maxIdle" value="${redis.pool.maxIdle}"/>
 8         <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"/>
 9         <property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
10     </bean>
11 
12     <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
13         <constructor-arg ref="jedisPoolConfig"/>
14         <constructor-arg value="${jedis.host}" type="java.lang.String"/>
15         <constructor-arg type="int" value="${jedis.port}"/>
16     </bean>

redis.properties

 1 # 控制一個pool可分配多少個jedis實例
 2 redis.pool.maxTotal=1000
 3 # 控制一個pool最多有多少個狀態為idle(空閑)的jedis實例
 4 redis.pool.maxIdle=200
 5 # 表示當borrow一個jedis實例時,最大的等待時間,如果超過等待時間,則直接拋出JedisConnectionException
 6 redis.pool.maxWaitMillis=2000
 7 #在borrow一個jedis實例時,是否提前進行validate操作;如果為true,則得到的jedis實例均是可用的
 8 redis.pool.testOnBorrow=true
 9 # redis 單機
10 # 單機 host
11 jedis.host=127.0.0.1
12 # 單機 port
13 jedis.port=6379

看了上面的代碼,我們知道一般的緩存是怎么使用的,在這個案例中,每個redisKey是根據請求的用戶名拼接特定的字符串生成的,每個請求用戶對應的key只在redis中保存一定的時間,過了指定的過期時間REDIS_TTL,數據將會被清除掉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM