关于springboot:京淘day11Redis缓存

3次阅读

共计 8500 个字符,预计需要花费 22 分钟才能阅读完成。

1. 系统优化策略

阐明: 引入缓存机制能够无效的升高用户拜访物理设施的频次, 从而进步响应速度.

2. 如何设计缓存

1. 缓存数据如何存储? 应该采纳什么样的数据结构呢? K-V key 的唯一性
2. 缓存数据的容量大小 应该动静保护缓存数据, 将不须要的数据提前删除. LRU 算法 /LFU 算法 / 随机算法 /TTL 算法
3. 缓存数据保留到内存中, 然而内存的特点断电即擦除. 定期将内存数据长久化(写入磁盘中)
4. 单台缓存服务器性能有余, 所以个别须要搭建集群(实现高可用).
5. 应用 C 语言开发.

3.Redis 缓存服务

3.1 什么是 Redis

Redis 是一个开源(BSD 许可)的,内存中的数据结构存储系统,它能够用 作数据库、缓存和消息中间件。 它反对多种类型的数据结构,如 字符串(strings),散列(hashes),列表(lists),汇合(sets),有序汇合(sorted sets) 与范畴查问,bitmaps,hyperloglogs 和 天文空间(geospatial)索引半径查问。Redis 内置了 复制(replication),LUA 脚本(Lua scripting),LRU 驱动事件(LRU eviction),事务(transactions)和不同级别的 磁盘长久化(persistence),并通过 Redis 哨兵(Sentinel)和主动 分区(Cluster)提供高可用性(high availability)。
速度: 读: 11.2 万 / 秒 写:8.6 万 / 秒 50 万 / 秒

3.2 上传 Redis

1). 上传 redis

2). 解压 redis 服务
[root@localhost src]# tar -xvf redis-5.0.4.tar.gz
3). 挪动文件 / 批改文件名称

3.3 装置 Redis

阐明: 在 Redis 根目录中执行如下命令
1).make

2). make install

3.4 批改 redis 配置文件

批改 redis 根目录下的 redis.conf 文件
1). 去除 IP 绑定

2). 批改保护模式

3). 开启后盾启动

4.Redis 服务器命令

阐明: Redis 服务在运行时, 必须依赖于配置文件 redis.conf. 操作 redis 时最好在根目录中操作
1). 启动 redis

redis-server redis.conf


2). 进入 redis 客户端

redis-cli -p 6379
ctrl + c 退出客户端


3). 敞开 redis 服务器

redis-cli -p 6379 shutdown


办法二:
阐明: 如果操作的端口号是默认端口 6379 则能够省略不写.
1). 启动 redis

redis-server redis.conf

2). 进入 redis 客户端

redis-cli 

3). 敞开 redis 服务器

redis-cli shutdown

4.SpringBoot 整合 Redis

4.1 整合入门案例

4.1.1 导入 jar 包

`<!--spring 整合 redis redisTemplate Spring 封装 jedis 高级 API-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>` 

4.1.2 实现测试案例

4.2 测试根本命令

package com.jt.test;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
//@SpringBootTest
public class TestRedis {
    // 链接服务: IP 地址: 端口
    @Test
    public void testSetGet() throws InterruptedException {Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.flushAll();   // 先清空 redis 缓存
        //1. 存取 redis
        jedis.set("key1", "天天向上");
        String value = jedis.get("key1");
        System.out.println(value);
        //2. 判断 key 是否存在
        if(jedis.exists("key1")){jedis.set("key1", "好好学习, 天天向上");
        }else{jedis.set("key1", "天天开心");
        }
        //3. 为 key 增加超时工夫
        jedis.expire("key1", 10);
        Thread.sleep(2000);
        System.out.println("残余存活工夫:"+jedis.ttl("key1"));
        //4. 撤销残余超时工夫
        jedis.persist("key1");
        System.out.println("撤销胜利!!");
    }
}

4.2.1 setNx/setEx/set 命令

   /**
     * 需要: 如果数据不存在, 则将数据批改
     */
    @Test
    public void testSetNx(){Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.set("key1", "aaa");
        // 如果 key 不存在, 则赋值
        jedis.setnx("key1", "测试方法");
        System.out.println(jedis.get("key1"));
    }
    /**
     * 需要: 实现超时工夫的设定与赋值操作的原子性.
     * 考点: 为数据设定超时工夫时, 切记满足原子性要求.
     *      否则会呈现 key 永远不能删除的景象
     */
    @Test
    public void testSetEx(){Jedis jedis = new Jedis("192.168.126.129",6379);
        /*jedis.set("key2", "bbb");
        jedis.expire("key2", 3);*/
        //??? 数据超时之后肯定会被删除吗???  错的
        jedis.setex("key2", 10, "bbb");
    }
    /**
     * 需要: 如果数据存在时, 才会批改数据, 并且为数据增加超时工夫 10 秒(原子性).
     * 参数阐明:
     *      NX: 只有数据不存在时, 才会赋值.
     *      XX: 只有数据存在时, 才会赋值.
     *      EX: 秒
     *      PX: 毫秒
     */
    public void testSet(){Jedis jedis = new Jedis("192.168.126.129",6379);
       /* if(jedis.exists("key3")){jedis.setex("key3",10 ,"ccc");
        }*/
        SetParams setParams = new SetParams();
        setParams.xx().ex(10);
        // 将所有的操作采纳原子性的形式进行管制
        jedis.set("key3", "ccc", setParams);
    } 

4.2.2 测试 hash

   /**
     * HASH 测试
     */
    @Test
    public void testHash(){Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.hset("person", "id", "100");
        jedis.hset("person", "name", "tomcat 猫");
        System.out.println(jedis.hgetAll("person"));
    }

4.2.3 测试 List

   /**
     * LIST 汇合测试
     */
    @Test
    public void testList(){Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.lpush("list", "1","2","3","4");
        String value = jedis.rpop("list");
        System.out.println(value);
    }

4.2.4 测试事务

   /**
     * Set 汇合测试
     *  1. sadd  新增元素
     *  2. SCARD  获取元素数量
     *  3. SINTER key1 key2  获取元素的交加
     *  4. SMEMBERS set      获取汇合元素
     *  demo 本人补一下
     */
    @Test
    public void testMulti(){Jedis jedis = new Jedis("192.168.126.129",6379);
        // 开启事务
        Transaction transaction = jedis.multi();
        try {transaction.set("a", "a");
            transaction.set("b", "b");
            // 提交事务
            transaction.exec();}catch (Exception e){
            // 回滚事务
            transaction.discard();}
    } 

5.SpringBoot 整合 Redis 的理论使用

5.1 编辑 properties 配置文件

5.2 编辑配置类

package com.jt.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.Jedis;
@Configuration// 标识是个配置类, 个别与 @Bean 注解连用
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {@Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;
    @Bean
 public Jedis jedis(){return new Jedis(host,port);
    }
}

6.ObjectMapperUtil 实现

6.1 业务需要

阐明: 在业务中通常须要将业务对象转化为 JSON 数据. 须要通过工具 API 进行手动的转化.

6.2 入门案例

public class TestObjectMapper {
    //objectMapper 入门案例
    //2. 将 JSON 转化为对象
    @Test
    public void testObject() throws JsonProcessingException {
        //1. 将对象转化为 JSON
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(100L)
                .setItemDesc("我是一个测试数据")
                .setCreated(new Date())
                .setUpdated(itemDesc.getCreated());
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(itemDesc);
        System.out.println(json);
        //2. 将 JSON 转化为对象
        ItemDesc desc = objectMapper.readValue(json, ItemDesc.class);
        System.out.println(desc);
    }
    @Test
    public void testList() throws JsonProcessingException {List<ItemDesc> list = new ArrayList<>();
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(100L).setItemDesc("我是一个测试数据").setCreated(new Date()).setUpdated(itemDesc.getCreated());
        ItemDesc itemDesc2 = new ItemDesc();
        itemDesc2.setItemId(200L).setItemDesc("我是一个测试数据").setCreated(new Date()).setUpdated(itemDesc.getCreated());
        list.add(itemDesc);
        list.add(itemDesc2);
        //1. 将对象转化为 JSON
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(list);
        System.out.println(json);
        //2. 将 JSON 转化为对象
        List<ItemDesc> list2 = objectMapper.readValue(json,list.getClass());
        System.out.println(list2);
    }
}

6.3 编辑 ObjectMapperUtil

public class ObjectMapperUtil {private static final ObjectMapper MAPPER = new ObjectMapper();
    public static String toJSON(Object target){
        try {return MAPPER.writeValueAsString(target);
        } catch (JsonProcessingException e) {e.printStackTrace();
            // 将查看异样转化为运行时异样.
            throw new RuntimeException(e);
        }
    }
    public static <T> T toObject(String json,Class<T> targetClass){
        try {return MAPPER.readValue(json, targetClass);
        } catch (JsonProcessingException e) {e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

7. 实现商品分类缓存操作

7.1 编辑 ItemController

 /**
     * 业务需要: 实现商品分类树形构造展示
     * url 地址:   http://localhost:8091/item/cat/list
     * 参数:      id= 父级节点的 ID
     * 返回值:    List<EasyUITree>
     */
    @RequestMapping("/list")
    public List<EasyUITree> findItemCatList(Long id){
        // 临时只查问一级商品分类信息
        long parentId = (id==null?0:id);
        //return itemCatService.findItemCatList(parentId);
        return itemCatService.findItemCatCache(parentId);
    }

7.2 编辑 ItemService

package com.jt.service;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.ItemCatMapper;
import com.jt.pojo.ItemCat;
import com.jt.util.ObjectMapperUtil;
import com.jt.vo.EasyUITree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import java.util.ArrayList;
import java.util.List;
@Service
public class ItemCatServiceImpl implements ItemCatService{
    @Autowired
    private ItemCatMapper itemCatMapper;
    @Autowired(required = false)  // 相似于懒加载
    private Jedis jedis;
    @Override
    public ItemCat findItemCatById(Long itemCatId) {return itemCatMapper.selectById(itemCatId);
    }
    /**
     * 1. 依据 parentId 查问子级目录信息
     * 2. 获取 ItemCatList 汇合, 之后将 List 汇合转化为 VOList 汇合
     * 3. 返回数据
     * @param parentId
     * @return
     */
    @Override
    public List<EasyUITree> findItemCatList(long parentId) {QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        List<ItemCat> catList = itemCatMapper.selectList(queryWrapper);
        //2 list 汇合转化
        List<EasyUITree> treeList = new ArrayList<>(catList.size());
        for (ItemCat itemCat : catList){long id = itemCat.getId();
            String text = itemCat.getName();
            String state = itemCat.getIsParent()?"closed":"open"; // 是父级, 默认应该 closed
            EasyUITree easyUITree = new EasyUITree(id, text, state);
            treeList.add(easyUITree);
        }
        return treeList;
    }
    /**
     * 实现步骤:
     *      1. 先定义 key     ITEM_CAT_PARENT::0
     *      2. 先查问缓存
     *          有  true    获取缓存数据之后, 将 JSON 转化为对象 之后返回
     *          没有 false   应该查询数据库, 之后将数据保留到 redis 中. 默认 30 天超时.
     * * @param parentId
     * @return
     */
    @Override
    public List<EasyUITree> findItemCatCache(long parentId) {Long startTime = System.currentTimeMillis();
        List<EasyUITree> treeList = new ArrayList<>();
        //1. 定义 key
        String key = "ITEM_CAT_PARENT::"+parentId;
        //2. 从缓存中获取对象
        if(jedis.exists(key)){
            // 存在  间接获取缓存数据, 之后转化为对象
            String json = jedis.get(key);
            treeList =  ObjectMapperUtil.toObject(json,treeList.getClass());
            System.out.println("查问 redis 缓存, 获取数据");
            long endTime = System.currentTimeMillis();
            System.out.println("耗时:"+(endTime-startTime)+"毫秒");
        }else{
            // 不存在  应该先查询数据库, 之后将数据保留到缓存中.
            treeList = findItemCatList(parentId);
            String json = ObjectMapperUtil.toJSON(treeList);
            jedis.setex(key, 7*24*60*60, json);
            System.out.println("查询数据库获取后果");
            long endTime = System.currentTimeMillis();
            System.out.println("耗时:"+(endTime-startTime)+"毫秒");
        }
        return treeList;
    }
}
正文完
 0