查询优化技术之多级缓存(数据库)

缓存设计原则

  • 用快速存取设备,用内存
  • 将缓存推到离用户最近的地方
  • 脏缓存处理(关键数据存储到数据库,数据库数据与缓存中数据的一致性问题)

多级缓存

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中缓存的数据,可以做到实时的更新

在这里插入图片描述

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