• redis 总结


    redis:

    遇到什么问题?

    当我们的系统引入了传统的缓存框架,比如(ehcache),因为ehcache等框架只是一个内置的缓存框架,所以前端的缓存和后台的(每一个webserver)的缓存都是独立存在的,加入一个缓存的数据发生了更新,其他缓存是不可能知道的,正阳对于乐观锁,总会提示失败;

    在分布式环境下,缓存不能同步;

    解决方案?

    让缓存集中处理(大家使用同一个缓存服务),我们需要一个类似于MYSQL这样可以通过服务来提供第三方的缓存工具(缓存服务器),流行的第三方缓存服务器有:memcache、redis

    理解:

    redis可以堪称一个Map(key-value),在redis中,所有的key都可以理解为byte[](string),

    VALUE?在memcache中,value也只能是byte[](string); ---------------->  Map<String,String> 。

          在redis中,value的可选类型很多,string,list,set,orderset,hash,Map<String,String>,Map<String,Set>,Map<String,String>,Map<String,Map<>>

    redis的优势:

    性能极高 ---- Redis能支持超过10w美妙的读写频率

    丰富的数据类型 ---- Redis支持二进制案例的Strings,Lists,Hashes,Sets及OrderedSets数据类型操作。

    原子 ---- Redis的所有操作都是原子性的,同事Redis还支持对几个操作合并后的源自性执行(简单的事务)。

    丰富的特性 ---- Redis还支持publish/subscribe(发布/订阅),通知,key过期等等特性。

    Redis的理念:

    我们常用的数据库:关系型数据库,面向对象数据库,NoSQL(Not only SQL) --> (key-value)内存数据库;

    redis是一个key-value的内存存储应用(使用redis主要还是吧数据存在内存中,这个可以最大的使用redis的性能优势);

    redis可以把数据存储在内存中,也可以持久化到磁盘上;

    redis不是一个适用于任何场景的存储应用;

    redis不光可以作为一个缓存,还是一个搞笑的额内存数据库;可以在某些情况下,高效的替换到传统的关系型数据库,非常好的处理高并发高请求的场景;

    学redis:

    redis在线入门:http://try.redis.io/

    redis中文资料站:http://www.redis.cn

    redis命令手册:http://www.redisdoc.com

    redis入门

    两个最基本的redis命令:

      SET KEY VALUE : 把VALUE保存到redis中KEY对应的值;

      GET KEY : 取出redis中KEY对应的值。

    关于redis中的key:

    在示例中,key的值为server:name  ,代表server的name,这是redis中key取名的一个规范;

    我们之前说到redis不光是一个缓存,还可以看作一个数据库,这种数据库和传统的关系型数据库最大的区别就在于,传统的关系型数据库,再保存数据库之前,都已经有一个固定的schema;内容是保存在一个schema中不同行的数据;所欲的数据都存在一张指定的表中,所有的内容都对应表里的一个指定行,每一个行都有固定的数据类型;

    所以,当我们在使用关系型数据表表现一个对象(数据结构的时候),我们能够事前通过schema规范好这个对象的结构;

    比如,要表现User这个对象,只需要创建一个user表,在表里面创建id、name、password桑额咧,在保存数据时。就是直接把数据保存到这个表中对应的列中,要查询id为1的user,可以通过select语句去表的内容中进行结构化的筛选;

    但是,对于redis来说,整个数据库就是一个Map,没有任何结构而言,所有通过set等方法扔到redis中的数据,可以简单理解为就是所有的数据乱七八糟的放在一个map中;

    问题:在redis中,怎么存储一个user?怎么检索?(Map能不能通过value查询???不能,换那句话说,在redis中,要能够支持查询的属性,都必须反映在key上)

    redis的作用:1、反映数据的结构;2、反映查询的内容。

    redis的版本

    目前稳定的最新版时3.2;

    redis时*Unix的一个用,我们在开发中使用的windows版本不是官方的,时微软开源提供的,每一个版本都对应一个linux版本的redis;

    注意32位和64位版本的区别。

    redis的基本概念

    1、redis也有数据库的概念,一个数据库中可以保存一组数据;

    2、哥哥数据之间时相互隔离的,当然也可以在不同数据库之间复制数据

    3、一般一个应用会单独使用一个数据库;

    4、每一个数据库都有一个id号,默认的数据id为0;

    5、可以使用select命令选择当前使用的数据库;

    6、redis 默认为我们创建16个数据库,这个参数可以在redis配置文件中使用databases来修改.

    Command(命令)

    1、redis中提供了非常大量和的命令来方便二点操作数据库中的数据,还可以使用redis中的一些特性;

    2、redis的命令可以简单理解为mysql的SQL命令;

    3、redis命令分为

    • 数据库的操作;
    • 发布/订阅相关操作;
    • 失误操作;
    • 脚本命令;
    • 连接服务器命令;
    • 数据库服务相关命令;

    KEY-VALUE

    1、key用来标记一个数据;一般在key中需要尽量标明数据的名字(还可以用key来表明数据所属类型),比如用于标示一个对象的额时候,可以使用user:1000来作为key,代表id为1000的用过户对象;

    2、value用来表示一个key对应的值;在redis中,数据可以是任何内容,redis把所有的value都作为byte来处理;所以可以用来保存任何内容;

    例子:像redis中存储一个json字符串;

      set user:1'{"id":1,"name":"stef","age":18}'

    获得这个值:

      get user:1

    3、redis最突出的特点是提供了5中常用的数据存储类型(value的类型),深刻理解这5种数据结构和各自的使用场景,对redis的使用有很大帮助;

    Query(检索)

    1、在redis中,不支持对value进行任何形式的查询;

    例如:保存一个user:

      set user:1'{name:"hello",id:1}'

    是无法通过redis去查询name为hello的user要查询的内容,只能反映在key值上,所以如果要按照用户的name查询,只能再添加一条数据;

    set user:name:stef 1

    2、redis不是一个适用于任何场景的存储方案,考虑使用redis需要对业务进行考评,用redis的思想去重新涉及数据结构;

    存储

    1、redis可以作为内存数据库,也可以把数据持久化到磁盘上;大部分情况下,都是把redis作为内存数据库。

    2、默认情况下,redis每60秒/1000数据修改或者15分钟/9个以下key修改;

    在redis配置文件中:

    save 500 1

    save 300 10

    save 60 10000

    3、数据默认存储在安装目录下,rdb文件中(可以在配置文件中dbfilenamedump.rdb配置);

    4、redis也可以设置为append模式,每次key的修改都会append到文件中,这种方式有可能丢失60秒的数据;

    • 通过配置:appendonly yes 开启
    • appendfilename "appendonlyaof"设置append文件;
    • 可以设置append模式(类似于mysql的事务文件同步机制);
      • appendfsync always:每次更新key及时同步到append文件;
        •   appendfsync everysec:每一秒同步一次jkey的更新
      • appendfsync no:不管理append文件的更新,根据操作系统去定。

     redis中的数据结构:

    redis中丰富的数据机构是redis区别memecache等其他NOSQL的一个重要优势;学习redis中的5种数据结构对使用redis有非常大的帮助;

    怎么学习redis中的数据结构和相关的额操作;

    1、熟悉数据结构的意义,最简单的方法和c++/java的数据类型对比;

    2、了解数据结构常用的一些命令(看文档,学会看懂文档中命令的意思和使用方式)

    3、尝试使用这些命令,做简单的实验(可以不需要场景,就只是看结果);

    4、了解该数据结构的使用场景(文档/网上资料),设计一个具体的场景,使用有效的命令完成场景操作;

    5、了解该数据结构的实现原理,了解二数据结构的执行效率(进阶)

    Redis中的string:

    1、redis中最常见的数据类型;内容可以是任何值(因为string对应着byte[]);

    2、可以通过set key value添加一个值;

    3、常见的字符串操作:

    • strlen key: : 返回key的value的值长度;
    • getrange key X Y : 返回key对应value的一个子字符串,位置从x到y;
    • append key value : 给key对应的value追加值,如果key不存在,相当于set一个新的值;

    4、如果字符串的内容是数值(integer,在redis中,数值也是string)

    • incr key : 给定key的value上增加1;(常用于id);redis中的一个源自操作,支持并发;如果key不存在,则相当于设置1;
    • incrby key value:给定key的value上增加value值;相当于key=key.value+value;也是一个原子操作;
    • decr : 给定key的value上减1;
    • decrby key value : 给定key的value上减value值;

    5、string最常见的使用场景:

    存储json类型对象 

    incr user:id

    set user:1 {id:1,name:alex}

    incr user:id

    set user:2 {id:2,name:cthon}

    作为计数器,

      incr count;

    优酷视频点赞

      incr vedio:100:goodcount  (id为100的视频点赞数加1)

      decr vedio:100:goodcount(id为100的视频点赞数减1)

    redis中的list

    1、redi的list结构,是一个双向链表,可以用来存储一组数据;从这个列表的前端和后端取数据效率非常高;

    2、list的常用操作:

    • RPUSH:在一个list最后面添加一个元素
      • RPUSH friends "stef"
    • LPUSH:在一个list最前面添加一个元素
      • LPUSH friends "stea"
    • LTRIM key start stop:剪裁一个列表,剩下的内容从start到stop;
      • LTRIM friends 0,3 => 只剩下前4个数据
    • LRANGE :获取列表中的一部分数据,两个参数,第一个参数代表第一个获取元素的位置<0>开始,第二个值代表截至的元素位置,如果第二个参数为-1,戒指到列表尾部;
      • LRANGE friends 0 -1
    • LLEN:返回一个列表当前长度
      • LLEN friends
    • LPOP:移除list中第一个元素,并返回这个元素
      • LPOP friends
    • RPOP:移除list中最后一个元素,并返回这个元素
      • RPOP friends

     3、list使用场景

    场景一:可以使用list模拟队列,堆,栈

    场景二:微博/微信朋友圈点赞

      规定:朋友圈内容的格式

        1、内容:user:x:post:x content 来存储

        2、点赞:post:x:good list 来存储

    • 创建一条微博内容:set user:1:post:91 "hello redis"
    • 点赞:
      • lpush post:91:good '{id:1,name:stef,img:xxx.jpg}'
      • lpush post:91:good '{id:1,name:x1,img:xxx.jpg}'

      • lpush post:91:good '{id:1,name:xm,img:xxx.jpg}'
    • 查看有多少人点赞:llen post:91:good
    • 查看有哪些人点赞:lrange post:91:good 0 -1

    思考:如果用数据库实现这个功能,SQL会多复杂?

    场景三:回帖

    • 创建一个帖子:set user:1:post:90 'wohenshuai'
    • 创建一个回帖:set postreply:1 'nonono'
    • 把回帖和帖子关联:lpush post:90:replies 1
    • 再来一条回帖:set postreply:2 'hehe'
        • lpush post:90:replies 2
    • 查询帖子的回帖:lrange post:90:replies 0 -1
        • get postreply:1

    redis中的set

    1、结构和java中差不多,数据没有顺序,并且每一个值不能重复;

    2、set结构的常见操作:

    • SADD:给set添加一个元素
      • SADD language 'java'
    • SREM:从set中移除一个给定元素
      • SREM language 'php'
    • SISMEMBER:怕那段给定的一个元素是否在set中,如果存在,返回1,如果不存在,返回0;
      • sismember language 'php'
    • SMEMBERS:返回指定set内所有的元素,以一个list形式返回
      • smembers language
    • SCARD:返回set的元素个数
      • scard language
    • SRANDMEMBER key count:返回指定set中随机的count个元素
      • srandmember friends 3 //随机推荐3个用户(典型场景,抽奖)
    • SUNION:综合多个set的内容,并返回一个list的列表,包含综合后的所有元素;
      • safdd language 'php'
      • sadd pg 'c'
      • sadd pg 'c++'
      • sadd pgs 'java'
      • sadd pgs 'swift'
      • sunion language pg pgs
    • SINTER key [key ...]:获取多个key对应的key之间的交集
      • SINTER friends:user:100 friends:user:1001 friends:user:1002 => 获取1000,1001,1002三个用户的共同好友列表;
    • SINTERSTORE destination key [key ... ] :获取多个key对应的set之间的交集,并保存为新的key值;目标也是一个set;
      • SINTER groupfriends friends:user:1000 friends:user:1001 friends:user:1002 => 获取三个用户共同的好友列表并保持存为组好友列表;

    3、set的使用场景

    • 去重
    • 抽奖
      • 准备一个抽奖池:
        • sadd luckdraws 1 2 3 4 5 6 7 8 9 10 11 12 13
      • 抽三个三等奖:
        • srandmember luckdraws 3
        • srem luckdraws 11 1 10
      • 抽2个二等奖:
    • 做set运算(好友推荐)
      • 初始化好友圈
        • sadd user:1:friends 'user:2' 'user:3' 'user:5'
        • sadd user:2:friends 'user:1' 'user:3' 'user:6'
        • sadd user:3:friends 'user:1' 'user:7' 'user:8'
      • 把user:1的好友的好友集合做并集;
        • user:1 user:3 user:6 user :7 user:8 
        • sunionstore user:1:maybe:group user:2:friends user:3:friends
        • smembers user:1:maybe:group
      • 让这个并集和user:1的好友集合和这个并集做差集;
        • user:1 user:6 user:7 user:8
        • sdiffstore user:1:maybe:group user:1:maybe:group user:1:friends
          • smembers user:1:maybe:group
      • 从差集中去掉自己
        • user:6 user:7 user:8
        • srem user:1:maybe:group user:1
      • 随机选取推荐好友
        •  srandmember user:1:maybe:group 2

    redis中的sorted-set(又叫zset)

    1、set是一种非常方便的结构,但是数据无序,redis提供了一个sorted set,每一个添加的值都有一个对应的分数,可以通过这个分数进行排序

    2、sortedset的常用操作:

    • ZADD:添加一个带分数的元素,也可以同事添加多个:
      • ZADD hackers 1940 "Alan Kay"
      • ZADD hackers 1906 "Grace Hopper"
      • ZADD hackers 1969 “Linux Torvalds”
      • ZADDhackers 1940 "Alan kay" 1960 "Grace Hopper" 1969 "Linux Torvalds"
    • ZCOUNT key min max : 给定范围分数的元素个数
      • ZCOUNT hackers 1940 1960 => 1940到1960的hacker个数
    • ZRANK key member : 查询指定元素的分数在整个列表中的排名(从0开始)
      • ZRANK hackers “Alan Kay" => alan kay 的年龄在所有hacker中的排名;
    • zrange hacke 0 -1 =>
      • "Grace Hopper"
      • "Alan Kay"
      • "Linus Torvald"
    • ZREVERANGE key start stop :按照分数从小到大排序

    3、sorted set 的使用场景:sorted set算是redis中最有用的一种结构,非常适合用于做海量数据的排行(比如一个巨型游戏的用户排名);sorted set中所有的方法都建议学一下;sortedset的速度非常快;

    示例1:

    • 天梯排名:
      • 添加初始排名和分数;
      • 查询fat在当前adder中的排名;
      • 查询ladder中的前3名;
      • steb增加了20ladder score;

    示例2:FIFO LIFO

    • LRU淘汰最长时间没使用;
    • LFU淘汰最低使用频率;

    redis中的hash

    1、hashes可以理解为一个map,这个map有一对一对的字段和值组成,所以,可以用hashes来保存一个对象;

    2、hashes的常见操作:

    • HSET : 给一个hasheds添加一个field和value;
      • HSET user:1000 name "John Smith"
      • HSET user:1000 email "john.smith@example.com"
      • HSET user:1000 password "s3cret"
    • HGET : 可以得到一个hashes中的某一个属性的值;
      • HGET user:1000 password "s3cret"
    • HGETALL : 一次性取出一个hashes中所有的field和value,使用list输出,一个filed,一个calue有序输出;
      • HGETALL user:1000 =>
        • "name"
        • "John Smith"
        • "email"
        • "john.smith@example.com"
        • "password"
        • "s3cret"
    • HMSET : 一次习惯的设置多个值(hashes multiple set)
      • HMSET user:1001 name "Mary Hones" password "hidden"  email "mjones@example.com"
    • HMGET : 一次性得到多个字段值(hashes multiple get),列表形式返回;
      • HMGET user:1001 name email =>
        • "Mary Jones"
        • "mjones@example.com"
    • HINCRBY : 给hashes的一个field的value值增加一个值(integer),这个增加操作时原子操作
      • HSET user:1000 visits 10
      • HINCRBY user:1000 visits 1 =>11
      • HINCRBY user:1000 visits 10 => 21
    • HKEYS : 得到一个key的所有fields字段,以list返回:
      • "name"
      • "password"
      • "email"
    • HDEL : 删除hashes一个指定的field;
      • HDEL user:1000 visits

     hash的使用场景:

    1、使用hash来保存一个对象更直观;(建议不适用hash来保存)

    2、分组

    • set user:id 1
    • set dept:id 1
    • HMSET ids user:id 1 dept:id 1 orderbill:id 1
    • HINCRBY ids user:id
    • HINCRBY ids dept:id
    • HMSET users user:1 "{id:1,name:xx}" user:2"{id:2,name:xx}"

    JAVA中对redis进行操作----jedis

  • 相关阅读:
    TypeError: run() missing 2 required positional arguments: 'rerun' and 'save_last_run'
    在wsl的ubuntu上安装vcpkg
    vscode + WSL +Ubuntu编程解决方案
    clion debug模式带参数运行程序
    关于jdk1.7之后String的intern方法的一点理解
    关于java中split的坑
    关于向HashMap存放数据出现顺序混乱的问题
    oracle外键禁用
    oracle复杂查询(二)
    oracle复杂查询(一)
  • 原文地址:https://www.cnblogs.com/cthon/p/9728457.html
Copyright © 2020-2023  润新知