查詢優化技術之多級緩存(數據庫)

緩存設計原則

  • 用快速存取設備,用內存
  • 將緩存推到離用戶最近的地方
  • 髒緩存處理(關鍵數據存儲到數據庫,數據庫數據與緩存中數據的一致性問題)

多級緩存

redis緩存

redis本質上是一個數據庫,
在這裏插入圖片描述

Redis商品詳情動態內容的實現

在商品詳情頁,當客戶端頻繁訪問某個數據庫的時候,可以將數據庫中查詢出來的內容緩存到redis中,下一次當客戶端發出同樣請求的時候不會訪問數據庫而訪問redis緩存。

    //商品詳情頁瀏覽
    @RequestMapping(value = "/get",method = {RequestMethod.GET})
    @ResponseBody
    public CommonReturnType getItem(@RequestParam(name = "id")Integer id){

        //根據商品的id到redis內獲取商品的詳情信息
        ItemModel itemModel = (ItemModel)redisTemplate.opsForValue().get("item_"+id);
        //若在redis內不存在對應的itemModel,則訪問下游的service
        if(itemModel==null){
            itemModel = itemService.getItemById(id);

            //若redis內沒有數據則將查詢出來的數據存儲到redis中
            redisTemplate.opsForValue().set("item_"+id,itemModel);
            //10分中之內不會反覆訪問數據庫
            redisTemplate.expire("item_"+id,10, TimeUnit.MINUTES);

        }


        ItemVO itemVO = convertVOFromModel(itemModel);

        return CommonReturnType.create(itemVO);

    }


在這裏插入圖片描述

對redis存儲的數據格式進行配置

public class RedisConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){

        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //首先解決key的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);

        //解決value的序列化方式
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper =  new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(DateTime.class,new JodaDateTimeJsonSerializer());
        simpleModule.addDeserializer(DateTime.class,new JodaDateTimeJsonDeserializer());

        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        objectMapper.registerModule(simpleModule);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

        return redisTemplate;




    }


//從rdis中獲取數據
“[“com.imooc.miaoshaproject.service.model.ItemModel”,{“id”:1,“title”:“iphone12”,“price”:[“java.math.BigDecimal”,21123],“stock”:97,“description”:”\xe4\xb8\x8d\xe9\x94\x99",“sales”:147,“imgUrl”:“https://i1.mifile.cn/a1/pms_1550642182.7527088!220x220.jpg”,“promoModel”:[“com.imooc.miaoshaproject.service.model.PromoModel”,{“id”:1,“status”:2,“promoName”:“iphone12”,“startDate”:“2020-06-01 08:39:47”,“endDate”:“2020-06-30 10:00:00”,“itemId”:1,“promoItemPrice”:[“java.math.BigDecimal”,10000]}]}]"

本地熱點緩存(在JVM中的緩存)—使用Guava cache

容量大小的限制,很難做到實時更新

  • 存放熱點數據
  • 髒讀不敏感
  • 內存可控

生命存活時間比redis中數據存活時間非常的短

  • HashMap
  • ConcurrentHashMap
  • Guava cache

Guava cache

  • 可控制的大小和超時時間
  • 可配置的lru策略
  • 線程安全

導入jar包


		<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>19.0</version>
		</dependency>

編寫緩存的處理方法

package com.imooc.miaoshaproject.service;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/6/27 0027  23:36
 */
//封裝本地哦緩存操作類
public interface CacheService {


    //存數據的方法
    void setCommonCache(String key,Object value);

    //取數據的方法
    Object getFromCommonCache(String key);




}


//實現類

package com.imooc.miaoshaproject.service.impl;

import com.imooc.miaoshaproject.service.CacheService;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * @Author Zhou  jian
 * @Date 2020 ${month}  2020/6/27 0027  23:37
 */
@Service
public class CacheServiceImpl implements CacheService {

    private com.google.common.cache.Cache<String,Object> commonCache = null;

    @PostConstruct
    public void init(){
        commonCache = com.google.common.cache.CacheBuilder.newBuilder()
                        //設置緩存容器錘石容量爲10
                        .initialCapacity(10)
                        //設置緩存中最大可以存儲100個key,超過100個之後會按照LRU的策略移除緩存向
                        .maximumSize(100)
                        //設置寫緩存後多少秒過期
                        .expireAfterWrite(60, TimeUnit.SECONDS)
                    .build();
    }

    @Override
    public void setCommonCache(String key, Object value) {
        commonCache.put(key,value);
    }

    @Override
    public Object getFromCommonCache(String key) {
        return commonCache.getIfPresent(key);
    }
}


在controller中實現


/商品詳情頁瀏覽
    @RequestMapping(value = "/get",method = {RequestMethod.GET})
    @ResponseBody
    public CommonReturnType getItem(@RequestParam(name = "id")Integer id){
        ItemModel itemModel = null;
        //1、先取本地更緩存
        itemModel = (ItemModel)cacheService.getFromCommonCache("item_"+id);

        if(itemModel==null){
            //根據商品的id到redis內獲取商品的詳情信息
            itemModel = (ItemModel)redisTemplate.opsForValue().get("item_"+id);
            //若在redis內不存在對應的itemModel,則訪問下游的service
            if(itemModel==null){
                itemModel = itemService.getItemById(id);

                //若redis內沒有數據則將查詢出來的數據存儲到redis中
                redisTemplate.opsForValue().set("item_"+id,itemModel);
                //10分中之內不會反覆訪問數據庫
                redisTemplate.expire("item_"+id,10, TimeUnit.MINUTES);

            }

            //存入本地緩存
            cacheService.setCommonCache("item_"+id,itemModel);


        }




        ItemVO itemVO = convertVOFromModel(itemModel);

        return CommonReturnType.create(itemVO);

    }

在這裏插入圖片描述
在這裏插入圖片描述

nginx proxy cache緩存

  • ngix反向代理時纔可以使用
  • 依靠文件系統存索引級的文件
  • 依靠內存緩存文件地址

這種方式不推薦,讀取的數據還是需要從磁盤中讀取,

nginx lua緩存

nginx lua腳本

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

OpenResty

在這裏插入圖片描述
在這裏插入圖片描述

使用lua shared dict:共享字典

OPenresy對Redis的支持

nginx讀取redis中緩存的數據,可以做到實時的更新

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章