• redis详解


     

    参考b站狂神说的视频

    https://www.bilibili.com/video/BV1S54y1R7SB?p=36&share_source=copy_web

    非关系型数据库:nosql数据库

    非关系型数据库的优点

    1。方便扩展(数据之间没有关系,很好扩展)

    2。大数据高性能(nosql的缓存记录数)

    3。数据类型是多样型的 (不需要事先设计数据库 随去随用)

     

    高性能 高可用  高可扩

     

    NOSQL的四大分类

    K V键值对.      ————->缓存 日志

    美团:redis tait

    阿里 百度:redis memcache

     

    文档型数据库    —————>分布式文件系统

    MongoDB(必须掌握) 

    基于分布式文件存储的数据库 C++编写,主要用来处理大量的文档

    mongoDB是一个介于关系型数据库和非关系型数据库的中间的产品。MongoDB是非关系型数据库中功能最丰富 最像非关系型数据库的

    ConthDB

     

    列存储数据库—-》web应用    HBase

    图关系数据库——-〉社交网络  Neo4j

     

    2.Redis是什么

    1.redis远程字典服务c语言编写,支持网络的,基于内存的可持久化 日志型,key value 数据库。支持多种语言的API

    免费和开源。 结构化数据库。

     

    作用:

    内存存储 持久化 (内存中是断电即失)(持久化 rdb aof)

    效率高 可以用于高速缓存

    发布订阅系统(简单消息队列)

    地图信息分析

    计时器 计数器

     

    特性

    1.多样的数据类型

    2.持久化

    3.集群

    4,事务

     

    测试性能

    Redis-benchmark 压力测试工具

    测试 100个并发 100000请求

    Refis-benchmark -h localhost -p 6379 -c 100 -n 100000

     

    Redis 推荐在linux上搭建

     

    3.Redis基础知识

    Redis默认有16个数据库  默认使用的第0个

    可以使用select进行切换数据库

    eg:select 3
    
     keys * 查看所有的key 
    
    flushall 清空所有的数据库
    
    flushdb 清空当前数据库
    

       

    Redis 是单线程的

    Redis是基于内存操作,CPU并不是redis的瓶颈,根据机器的内存和网络带宽

    为什么单线程还这么快?

    CPU>内存>硬盘

    Redis是将所有的数据都存在内存中,对于内存系统来说,没有上下文切换效率就是最高的。

     

    它可以用作数据库 缓存 消息中间件。

    支持多种类型的数据结构 字符串 散列 列表 集合 有序集合与范围查询

    redis的五大数据类型

    Redis-Key
    判断是否存在   exists key值
    移除指定的key值 Move key值 数据库
    设置过期时间,单位是秒  expire name 10
    查看key的剩余时间 ttl key值
    查看key的类型 type key值
    

    string

    set key值 value 赋值
    get key值 获取值
    APPEND key值 “hello” 拼接字符串
    如果key不存在就新建
    STRLEN key值 字符串长度
    incr key值  对应的值加1
    decr key值  对应的值减1
    INCRBY key值 步长 可以设置指定增量
    eg:INCRBY views 10 对应的值加10
    获取范围
    eg:set key1 “hello,zhangsan”
    GETRANGE key1 0 3
    “hell”
    GETRANGE key1 0 -1 //查看全部字符串
    “hello,zhangsan” 
    

      替换

    set key2 abcdefg
    SETRANGE key2 1 xx //替换指定位置开始的字符串
    get key2 ->axxdefg
    
    setex(set with expire) 设置过期时间
    eg:setex key3 30 “hello”
    setnx(set if not exists) 不存在设置
    eg:setnx mikes  “redis”
    

     批量获取和批量设置

    批量设置 mset
    eg: mset key1 value1 key2 value2 key3 value3
    批量获取 mget
    eg: mget key1 key2 key3
    msetnx key1 value1 key4 value4
    //msetnx是个原子性操作,一起成功 一起失败
    
    对象 设置一个user对象
    user:{id}:{filed}
    mset user:1:name zhangsan user:1:age 18
    mget user:1:name user:1:age
    1)”zhangsan”
    2)”18”
    

     先get后set

    getset  先get后set
    getset db redis ->(nil)
    get db —>redis
    Getset db mongdb —->redis
    get db—>mongdb
    

    string类型的应用:

    计数器

    统计数量

    统计多单位的数量

    对象缓存

     

    List

    列表  

    所有的list命令都是l开头的

    添加 LPUSH list one  //每次将数据插入头部
    
    LPUSH list two
    
    获取 LRANGE list 0 -1
    -》“two”
    -》“one”
    
    Rpush list right //每次将数据放到尾部
    
    LRANGE list 0 -1
    -》“two”
    -》“one”
    -》“Right

    LPOP 移除尾部的值

    RPOP 移除头部的值

    eg: Lpop list
    
    通过下标获取值
    
    LRAANGE list 0 -1
    -》two
    -》one
    
    Lindex list 0 —》two
     
    
    返回列表的长度
    Llen list —>2
    
    移除指定值。list可以重复 
    Lpush list three
    Lpush list three
    
    Lrem list 1 three //从list中移除一个three
    
     
    List 截断 
    
    Rpush mylist “hello”
    Rpush mylist “hello1”
    Rpush mylist “hello2”
    Rpush mylist “hello3”
    
    Ltrim mylist 1 2 //通过下标截取指定的长度
    
    Lrange mylist 0 -1
    ->“hello1”
    ->“Hello2”
    
     
    
    rpoplpush 移动list中最后一个值 并将其移动到新的列表中
    
    rRush mylist “hello”
    rRush mylist “hello1”
    rRush mylist “hello2”
    
    rpoplpush mylist myotherlist
    
    Lrange mylist 0 -1
    ->“hello”
    ->“hello1”
    
    Lrange myotherlist 0 -1
    ->“Hello2”
    
    
    lset  将列表中指定下标的值替换为另外一个值 更新操作
    如果列表不存在 更新会报错 如果下标的值存在更新,不存在 报错
    Linset 将某个具体的value 插入到list中某个元素的前面和后面
    
    Rpush mylist “hello”
    Rpush mylist “world”
    
    Insert mylist before world other
    ->“hello”
    ->“other”
    ->“World
    

    小结

    实际上是一个链表。

    如果key 不存在 创建新的链表

    在两边插入或者改动值 效率最高,中间元素,相对来说效率低一些 

    应用:消息队列

     

    Set (集合)

    不能重复

    所有的set命令都是s开头的 

    添加

     

    sadd myset “hello”
    sadd myset “kuangshen”
    
    获取所有元素 SMembers
    SMembers myset
    ->“hello”
    ->“kuangshen

     

    判断是否包含某个元素  Sismeber myset hello
    
    获取set集合的元素个数  scard myset
    
    移除某一个元素 Srem myset hello
    
    
    随机抽出一个元素 Srandmember myset Srandmember myset 2 随机抽取指定个数的元素

     

    随机移除set集合中的元素

    eg:SMembers myset
    ->Kuangshen2
    ->Kuangshen
    ->Hello
    
    Spop myset ->kuanghen2
    Spop myset —>kuangshen
    

      

    Smove 将一个指定的key 移动到另一个set 

    Sadd myset “hello”
    
    Sadd myset “world”
    
    Sadd myset2 “set2”
    
    Smove myset myset2 “hello
    
    Sadd key1 a
    Sadd key1 b
    Sadd key1 c
    
    Sadd key2 c
    Sadd key2 d 
    Sadd key2 e
    
    
    Sdiff key1 key2 //两个set集合的差集
    -> “b”
    -> “a”
    key1中key2没有的
    
    Sinter key1 key2//两个set集合的交集
    ->“c”
    
    SUnion key1 key2//并集

    Hash(哈希)

    Map 集合 key -map

    本质和string 没有什么太大区别

    所有的hash命令都是h开头的

    set myhash field1 kuangshen
    Hget myhash field1
    ->“Kuangshen”
    //值会被覆盖
    Hmset myhash field1 hello field2 world
    Hmget myhash field1 field2
    ->“hello”
    ->”world”
    Hgetall myhash
    ->“hello”
    ->”world”
    hdel myhash field1 //删除hash指定key值
    Hlen myhash //获取hash的长度
    Exists myhash field1//判定hash中指定的key是否存在
    Hkeys myhash//获取所有的key值
    Hvals myhash//获取所有的value值
    Hset myhash field3 5
    
    Hincrby myhash field3 1//给指定key值增加指定步长
    
    Hsetnx //如果存在不能设置 不存在就能设置
    
    Hash 变更的数据 user name age 更适合对象的存储
    Hset user:1 name “zhangsan”
    Hset user:1 age “18”

    应用:集合之间的操作。交集。并集  差集

    Zset 有序集合

    set的基础上,增加了一个值  

    set k1 v1 

    Set k1 score1 v1

    eg:Zadd myset 1 one
    Zadd myset 2 two 3 three
    Zrange myset 0 -1
    ->”one”
     “two”
     “three"
    
    排序
    
    
    Zadd salary 2500 xiaohong
    Zadd salary 5000 zhangsan
    Zadd salary 500 kuangshen
    
    
    ZRANGEBYSCORE salary -inf +inf
    ->“kuangshen”
    -> “xiaohong”
    -> “zhangsan"
    ZRANGEBYSCORE salary -inf +inf with scores
    ->”kuangshen”
    ->“500”
    ->“xiaohong”
    ->“2500”
    ->“zhangsan”
    ->“5000
    

    排序(上限)

    ZRANGEBYSCORE salary -inf 2500
    ->“kuangshen”
    ->“xiaohong
    Zrevrange salary 0 -1 (从大到小排序)
    -》“zhangsan”
    -》“Kuangshen”
    
    移除元素 zrem
    Zrem salary xiaohong
    
    查看元素个数
    Zcard salary
    
    Zconut 获取指定区间的成员数量
    Zadd myset 1 hello 2 world 3 kuangshen
    Zconut myset 1 3
    -> 3
    
    
    Zcont myset 1 2 获取指定区间的成员数量
    -〉2  

    小结:set 排序 存储班级成绩表 工资表排序

    普通消息 1,重要消息 2.带权重进行判断

     应用:排行榜应用实现

    三种特殊数据类型

     1.Geospatial 地理位置

    Redis  geo  可以推算地理位置的信息 两地之间的距离 方圆几里的人

    Geoadd key 值(纬度 经度 名称)

    规则:两极无法直接添加 一般会下载城市数据 直接java程序导入

    Geoadd china:city 116.40 39.90 beijing
    
    Geoadd china:city 121.47 31.23 Shanghai
    
    Geoadd china:city 106.50 29.53 Chongqing 114.05 22.52 Shenzhen

    有效的经度 -180 180

    有效的纬度 -85 85

     

    获取指定城市的经度和纬度

     

    Geopos china:city beijing
    ->”116.3999..”
    ->“39.90000

     

    Geodist 获取指定两个位置的距离(直线距离) 

    Geodist china:city beijing Shanghai km

     

    我附近的人?(获得所有附近的人的地址 定位)

    Georadius 以给定的经纬度为中心 找出某一半径内的元素

    Georadius China:city 110 30 500 km
    ->”chongqin”

     

    Georadius China:city 110 30 500 km withdist 直线距离

    Georadius China:city 110 30 500 km withcoord 经纬度

     

    获得指定数量的人

    Georadius China:city 110 30 500 km count 1

     

    北京周围的城市

    Georadiusbymember china:city beijing 100 km

     

    Geohash 返回一个或者多个位置元素的geohash表示

    将返回11个字符串的geohash字符串(将二维的经纬度转换为一维的字符串)

     

    Geo 底层的实现原理就是zset ,可以使用zset 命令来操作

     

     2.Hyperloglog PF开头的命令

    什么是基数?不重复的元素

    A135787

    B13578

    基数(不重复的元素)     网页的浏览量(一个人访问一个网站多次,但是还是算作一个人)

    占用的内存是固定的,2^64 不同的元素,只需要占用128kB内存

    0.81%错误率

    eg:PFADD mykey a b c d e f g h I j
    PFCOUNT mykey
    ->10
    
    PFADD mykey2 i j z x c v b n m
    PFCOUNT Mykey2
    ->9
    
    
    PFMEGRE mykey3 mykey mykey2
    PFCOUNT mykey3
    ->15

    如果允许有一定错误率,就可以用hyperloglog

     3.Bitmaps

    位存储 操作二进制来记录 

    统计用户信息 两个状态的 都可以使用Bitmaps

    周一到周六的打卡

    Setbit sign 0 1
    Setbit sign 1 0
    Setbit sign 2 0
    Setbit sign 3 1
    Setbit sign 4 1
    Setbit sign 5 0
    Setbit sign 6 0
    
    Getbit sign 6
    ->0
    
    
    Getbit sign 3
    ->1
    
    bitcount sign //统计打卡的天数
    ->3 

     

    Redis基本的事务操作

    事务

    一组命令的集合 一个事务中的所有命令都会被序列化 会按照顺序执行,

    一次性 顺序性 排他性 执行一些列的命令

    Redis事务没有隔离级别的概念 单条命令出错不会影响前面的任务 也不会影响后面的命令

    Redis 单条命令

    开启事务(multi

    命令入队()

    执行事务(exec)

    Multi //开启事务

    Set k1 v1

    Set k2 v2

    Get k2

    Set k3 v3

    exec //执行事务

    ->ok

    ->ok

    ->v2

    ->ok

    每个事务执行完就没有了

    放弃事务 discard 在事务执行之前可以放弃事务

     

    编译型异常(代码有问题,命令有错)事务中所有的命令都不会被执行

    运行型异常(如果事务队列中存在语法性错误,)执行事务的时候,其他命令会正常执行,错误命令抛出异常。

     

    乐观锁

    悲观锁:无论做什么都会加锁

    乐观锁:更新数据的时候去判断一下,在此期间,是否有人修改过这个数据,

    Mysql 获取version,更新的时候比较version

     

    Redis监视测试

    Set money 100
    
    Set out 0
    
    Watch money 监视money对象
    
    Muiti
    
    Decrby money 20
    
    Incrby out 20
    
    Exec  执行命令
    
    ->80
    
    ->20
    

      

    测试多线程修改值,使用watch可以当作redis的乐观锁操作

    Watch money
    Multi
    Decrby money 10
    Incrby out 10
    
    Exec 执行之前,另外一个线程,修改了我们的值,这个时候,就会导致我们事务执行失败
    ->(nil)

    如何解决?释放锁,重新写事务

    Unwatch

    Watch money

      

    Jedis

    使用java操作Redis

    Redis官方推荐的java连接开发工具,使用java操作redis中间件。

    导入包

    2.编码测试:

    连接数据库

    操作命令

    断开连接

     

    Jedis jedis = new Jedis("127.0.0.1",6379);

    System.out.println(jedis.ping());

    方法和之前的api完全相同

    Jedis.close();//关闭连接

    事务:
    public static void main(String[] args) {
        //
        Jedis jedis = new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
        jedis.flushDB();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","world");
        jsonObject.put("name","zhangsan");
        Transaction multi = jedis.multi();//开启事务
        String result = jsonObject.toJSONString();
        try {
            multi.set("user1",result);
            multi.set("user2",result);
            multi.exec();//执行事务
        }catch (Exception e){
            multi.discard();//销毁事务
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();
        }
    }
    

       

    springboot整合

    Springboot2.x之后。原来使用的jedis 被替换成了letture

    Jedis:采用的直连。 多线程操作的话,不安全,避免不安全就使用jedis pool连接池 

    Lettuce:采用netty,异步,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数量。

     

    导入包

    配置连接

    测试 

    传输对象需要序列化

    自定义的redisTemplate

     

    Redis.conf详解

    1.大小写不敏感

    2.可以包含其他配置文件

     

    Network

    Bind 127.0.0.1 绑定ip

    通用 general

    Demonize yes #后台运行 默认是no

    Loglevel notice #生产环境

    Logfile 日志文件名

    Database 16 #数据库的数量

    Always-show-logo yes #是否显示logo

     

     

    快照

    持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb .aof

    如果900秒至少有一个key 进行了修改,我们

    Save 900 1

    Save 300 10

    Save 60 10000

    Stop-writes-on-bgsave-error yes 持久化如果出错,是否继续工作

    Rdbcompression yes 是否压缩rdb文件,会消耗一些cpu资源

    Rdbchecksum yes 保存rdb文件的时候,进行错误的检查校验

    Dir ./ rdb文件保存的目录

     

    Requirepass 123456 #设置密码

    Config set require pass 123456

    Config get require pass

    ->noauth authentication required

    Auth 123456

    ->ok

     

    Append only 模式

    Appendonly no 默认是不开启,默认是使用rdb方式持久化,大部分所有的情况下,rdb完全够用

    Appendfsync everysec 每秒执行一次

     

    Redis持久化

    Redis是内存数据库,如果不将内存中的数据库保存到磁盘中,一旦服务器进程退出,数据库状态也会消失,所以redis提供了持久化功能

    默认是rdb 缺点就是最后一次持久化的数据可能会丢失

    保存的文件是dump.rdb

    触发规则

    1.save的规则满足的情况下,会自动触发rdb规则

    2.Flushall命令,也会触发我们的rdb规则

    3.退出redis,也会产生rdb文件

    备份就会自动生成一个dump.rdb

     

    如果恢复rdb文件的数据

    只需要将rdb文件

    放到我们的redis启动目录下,redis启动的时候会自动检查dump.rdb 恢复其中的数据

    查看需要的位置

    Config  get dir

    ->dir

    ->usr/local/bin如果在该目录下存在dump.rdb文件,启动就会自动回复其中的数据

    优点:

    适合大规模的数据恢复

    如果你对数据的完整性要求不高

    缺点:

    需要一定时间间隔进程操作,redis意外宕机了,最后一次修改数据就没了

    Fork进程的时候,会占用一定的内存空间

      

    AOF

    以日志的形式来记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),只许追加文件不许修改文件,redis启动之初就会读取该文件重新构建,

    AOF 保存的是appendonlyaof

    默认不开启 

    重启redis就可以生效了

    如果aof文件有错误,redis无法启动

    redis修复aof工具 redis-check-aof

    Redis-check-aof -fix appendonly.aof

    文件正常 重启就可以恢复

     

    优点:

    1.每次修改都同步,文件的完整性会更好

    2。每秒同步一次,可能会丢失一秒的数据

    3.从不同步,效率最高的

    缺点:

    1.相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb

    2.aof运行效率也比rdb慢,所以redis默认配置是rdb

     

    Rewite 重写

     

    发布订阅

    消息通信模式 发送者发送消息 订阅者接收消息

    消息发送者

    频道

    消息订阅者

    Subscribe 频道名 //订阅频道

    Publish 频道名 消息//向某频道发布消息

    Subscribe 频道名 //订阅多个频道

     

    Eg:

    订阅端:subscribe bilibili

    ->subscribe

    ->kuangshenshuo

    ->message

    ->bilibili

    ->hello,bilibili

    发送端:publish bilibili hello,bilibili

     

    Subscribe就是把订阅的人加入到该频道的发布链表中

    使用场景:

    实时消息系统

    实时聊天(聊天室)

    订阅 关注系统都是可以的

     

     

    主从复制 读写分离 

    Master -slave1

                -slave2

                -slave3

    主机进行读,从机进行写。减缓服务器的压力。

    数据的复制是单向的,只能由主节点到从节点。

    主从复制的作用:

    1。数据冗余

    2。故障恢复

    3。负载均衡  通过多个从节点分担负载

    4,高可用 

     

     

    单台redis的最大使用内存不应该超过20G

    默认情况下,每台redis都是主节点

    info replication 查看当前库的信息

    ->role:master 角色

    connected_slaves:0  没有从机

     

    复制3个配置文件,修改对应的信息

    1。端口

    2pid名字

    3log文件名字

    4dump.rdb名字

     

    启动服务 redis-server kconfig/redis79.conf

    连接        redis-cli -p 6379

    一主二从

     

    主从复制之复制原理

    默认情况下,每台redis都是主节点

    info replication //查看当前库的信息

    ->role:master //角色

     

    在从机中配置

    slaveof 127.0.0.1 6379//绑定对应的主机

     

    配置了之后,从机的角色变了 主机中可以看到从机的配置信息

     

    真实的主从配置  修改配置文件

    replicaof 主机IP 端口号

     

    主机可以写,从机不能写只能读 

    主机中的所有信息和数据,都会自动被从机保存

     

    测试:主机断开连接 从机依旧连接到主机的,这个时候,主机如果回来了,从机依旧可以直接获取到主机写的信息

    如果使用命令行 配置的主从,重启之后,又会变成主机,只要变成从机,立马就会从主机中获取值

     

    从机启动成功连接到主机后,会发送一条sync同步命令

    master接到命令后,启动后台的存盘进同时收集所有接收到的用于修改数据集命令,

    在后台命令执行完毕之后,master将传送整个数据文件到slave.完成一次完全同步

     

     全量复制  slave服务在接收到数据库文件数据后,将其存盘加载到内存中

     增量复制  master继续将新的所有收集到的修改命令依次传给slave,完成同步

    但是只要重新连接master ,一次全量复制将会被自动执行。

     

    层层链路

    Master -slave1 master  -slave2

         79       80                     81

    80为从节点,不能写 ,只能读

    slaveof no one

    如果主机断开了连接 使用slaveof no one 让自己成为主机

       

     

    哨兵模式(自动选举老大的模式)sentinel

    通过后台监控主机是否故障,如果故障了根据投票数自动将从库转为主库

    原理:哨兵通过发送命令 等待redis服务器响应 从而监控运行的多个redis实例

    多哨兵模式

    主服务器不能用 并且达到一定数量,让各个哨兵爸自己监控的从服务器实现切换主机,为客观下线

     

    配置哨兵配置文件 sentinel.conf

    Sentinel montior 被监控的名称  host port 1

    Sentinel montior myredis 127.0.0.1 6379 1

    后面的数字 代表主机挂了 slave投票看让谁接替成为主机 投票最多的,就会成为主机

    启动哨兵

    Reidis-sentinel kconfig/sentinel.conf

    如果主机节点断开了,就会从从机中随机选择一个服务器

    哨兵日志

    Failover 发现故障

    Sdown 主机转移

    如果主机此时回来。只能归并到新的主机下,当作从机

     

     

    优点

    1.哨兵集群,基于主从复值模式,所有的主从配置优点,它都有

    2.主从可以切换,故障可以转移,系统的可用性好

    3.哨兵模式就是主从模式的升级,手动到自动,更加健壮

    缺点

    Redis不好在线扩容,集群容量一旦到达上限,在线扩容十分麻烦

    实现哨兵模式的配置其实是很麻烦的,里面有很多选择。

     

    Redis缓存穿透与雪崩

    缓存穿透

    用户查询一个数据 redis内存数据库中没有,缓存没有命中,于是在持久层数据库查询

    发现也没有,于是本次查询失败,当用户很多,缓存都没有命中(秒杀),于是都去请求了持久层数据库,这就会给持久层数据库造成很大压力,出现了缓存穿透。

     

    布隆过滤器

    对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,避免了对底层存储系统的压力

    客户端 -bloomfilter  ->缓存层   -〉存储层

     

    缓存空对象

    没命中的空对象缓存起来,同时设置一个过期时间,之后再访问这个数据从缓存中获取

     

    问题:

    如果空值能够被缓存起来,这就意味着缓存需要更多空间,因为这当中可能有许多空值的键

    即使对空值设置了一个过期时间,还是会存在缓存层和存储层的数据会有一段时间的不一致,这对于需要保持一致性的业务会有影响。

     

    缓存击穿

    是指一个key非常热门,在不停的扛着高并发,这个key在失效的瞬间,持续的大并发就会穿透缓存,直接请求数据库。

     

    设置热点数据永不过期

    加分布式锁

    使用分布式锁,保证每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限

     

    缓存雪崩

    在某一个时间段,缓存集中过期失效,redis宕机

    停掉一些服务

     

    redis高可用

    多增几台redis

    限流降级

    这个解决方案的思想是,缓存失效时通过加锁或者队列控制数据库写缓存的线程数量

    数据预热

    数据预热的含义就正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动触发并加载缓存不同的key,设置不同的缓存过期时间,让缓存失效的时间尽可能均匀

     

  • 相关阅读:
    第十六周 项目一-平方根中的异常
    LeetCode之小孩分糖果
    C#中怎样将List<自己定义>转为Json格式 及相关函数-DataContractJsonSerializer
    (016)给定一个有序数组(递增),敲代码构建一棵具有最小高度的二叉树(keep it up)
    物化视图
    FZU2171:防守阵地 II(线段树)
    鸡尾酒排序
    Android BlueDroid(三):BlueDroid蓝牙开启过程enable
    CF Codeforces Round #256 (Div. 2) D (448D) Multiplication Table
    window.open()具体解释及浏览器兼容性问题
  • 原文地址:https://www.cnblogs.com/yxj808/p/15383914.html
Copyright © 2020-2023  润新知