数据库学习之旅——Redis

  • Redis介绍

    • 特点及优点

      1、开源的,使用C编写,基于内存且支持持久化
      2、高性能的Key-Value的NoSQL数据库
      3、支持数据类型丰富,字符串strings,散列hashes,列表lists,集合sets,有序集合sorted sets 等等
      4、支持多种编程语言(C C++ Python Java PHP ... )
      
    • 与其他数据库对比

      1、MySQL : 关系型数据库,表格,基于磁盘,慢
      2、MongoDB:键值对文档型数据库,值为JSON文档,基于磁盘,慢,存储数据类型单一
      3、Redis的诞生是为了解决什么问题??
         解决硬盘IO带来的性能瓶颈
      
    • 应用场景

      1、使用Redis来缓存一些经常被用到、或者需要耗费大量资源的内容,通过这些内容放到redis里面,程序可以快速读取这些内容
      2、一个网站,如果某个页面经常会被访问到,或者创建页面时消耗的资源比较多,比如需要多次访问数据库、生成时间比较长等,
      我们可以使用redis将这个页面缓存起来,减轻网站负担,降低网站的延迟,比如说网站首页等
      3、比如新浪微博
      # 新浪微博,基于TB级的内存数据库
      # 内容 :存储在MySQL数据库
      # 关系 :存储在redis数据库
      # 数字 :粉丝数量,关注数量,存储在redis数据库
      # 消息队列
      
    • DB-Engines 数据库流行度排行榜2019年11月最新排名

    • redis 版本

      1、最新版本:5.0
      2、常用版本:2.4、2.6、2.8
      	3.0(里程碑)、3.2、3.4、4.0、5.0
      3、图形界面管理工具(写的一般)
      	RedisDesktopManager
      # 为了解决负载问题,所以发明了redis
      
    • 诞生历程

      # 1、历史
      LLOOGG.com 帮助别的网站统计用户信息,各个网站发送的浏览记录都会存储到存储队列,5-10000条记录,多余5条需要收费
      
      # 2、原理
      FIFO机制,先进先出,满了进一条就出一条,网站越多,队列越多,推入和弹出操作越多
      
      # 3、技术及问题
      开始使用MySQL进行硬盘读写,速度很慢,导致无法实时显示,所以自己写了一个列表结构的内存数据库,程序性能不会受到硬盘IO的限制,加了持久化的功能
      
      # 4、redis数据库戛然而生
      
    • redis 附加功能

      1、持久化
        将内存中数据保存到磁盘中,保证数据安全,方便进行数据备份和恢复
      2、发布与订阅功能
         将消息同时分发给多个客户端,用于构建广播系统
      3、过期键功能
         为键设置一个过期时间,让它在指定时间内自动删除
         <节省内存空间>
         # 音乐播放器,日播放排名,过期自动删除
      4、事务功能
         原子的执行多个操作
      5、主从复制
      6、Sentinel哨兵
      

  • Redis安装

    • Ubuntu

      # 安装
      sudo apt-get install redis-server
      # 服务端启动
      sudo /etc/init.d/redis-server start | stop | restart | status
      # 客户端连接
      redis-cli -h IP地址 -p 6379 -a 密码
      redis-cli
      127.0.0.1:6379>ping
      PONG
      
    • Windows

      1、下载安装包
         https://github.com/ServiceStack/redis-windows/blob/master/downloads/redis-64.3.0.503.zip
      2、解压
      3、启动服务端
         双击解压后的 redis-server.exe 
      4、客户端连接
         双击解压后的 redis-cli.exe
      
      # 问题:关闭终端后服务终止
      # 解决:将Redis服务安装到本地服务
      1、重命名 redis.windows.conf 为 redis.conf,作为redis服务的配置文件
      2、cmd命令行,进入到redis-server.exe所在目录
      3、执行:redis-server --service-install redis.conf --loglevel verbose
      4、计算机-管理-服务-Redis-启动
      
      # 卸载
      到 redis-server.exe 所在路径执行:
      1、redis-server --service-uninstall
      2、sc delete Redis
      

  • 配置文件详情

    • 配置文件所在路径

      1、Ubuntu
      	/etc/redis/redis.conf
      
      2、windows 下载解压后的redis文件夹中
      	redis.windows.conf 
      	redis.conf
      
    • 设置连接密码

      1、requirepass 密码(500行)
      2、重启服务
         sudo /etc/init.d/redis-server restart
      3、客户端连接
         redis-cli -h 127.0.0.1 -p 6379 -a 123456
         127.0.0.1:6379>ping
      
    • 允许远程连接

      1、注释掉本地IP地址绑定
        69行: # bind 127.0.0.1 ::1
      2、关闭保护模式(默认开启,把yes改为no)
        88行: protected-mode no
      3、重启服务
        sudo /etc/init.d/redis-server restart
      
    • 远程连接测试(Windows连接Ubuntu的Redis服务)

      # cmd命令行
      1、d:
      2、cd Redis3.0
      3、redis-cli -h x.x.x.x
      4、x.x.x.x:6379>ping
          
      # RedisDesktopManage 连接,注意windows防火墙问题(关闭)
      

  • 数据类型

    • 字符串类型(string)

      • 特点

        字符串、数字、都会转化为字符串来存储

      • 基本命令

        1、set key value
        2、setnx key value
        3、set key value ex seconds
        4、get key
        5、mset key1 value1 key2 value2 
        6、mget key1 key2 key3 
        7、stren key 
        # 数字操作
        8、incr key
        9、decr key
        
      • 扩展命令

        1、append key value
        2、setrange key index value
        3、getrange key start stop
        4、incrby key step
        5、decrby key step
        
      • 常用命令

        set | get命令
        作用: 设置键值,获取键对应的值
        命令格式:  
        				set key value
                		get key
                		
        set命令之 - setnx 
        # 键不存在,进行设置,如果键已经存在,则不进行任何操作
        setnx key value : 键不存在时才能进行设置(重要)
        
        set命令之 - ex
        作用: 设置过期时间
        命令格式: set key value ex seconds
        
        mset | mget
        mset key1 value1 key2 value2 key3 value3 ... ...
        mget key1 key2 key3 ... ...
        作用: 同时设置多个值,获取多个值
        
      • 键命名规范

        利用层级关系
        mset  dayin:email  [email protected]  dy:email [email protected]
        
        
      • strlen命令

        作用: 获取值的长度
        命令格式: strlen key
        
        127.0.0.1:6379> strlen name
        (integer) 11
        127.0.0.1:6379> 
        
      • 字符串索引操作

        setrange key 索引值 value
        作用: 从索引值开始,value替换原内容
        
        127.0.0.1:6379> get message
        "hello world"
        127.0.0.1:6379> setrange message 6 'dayin'
        (integer) 12
        127.0.0.1:6379> get message
        "hello dayin"
        127.0.0.1:6379> 
        
        
        getrange key 起始值 终止值
        作用: 获取指定范围切片内容
        127.0.0.1:6379> get message
        "hello dayin"
        127.0.0.1:6379> getrange message 0 4
        "hello"
        127.0.0.1:6379> getrange message 0 -1
        "hello dayin"
        
      • append key value

        作用: 追加拼接value的值
        
        127.0.0.1:6379> set message 'hello '
        OK
        127.0.0.1:6379> append message 'world'
        (integer) 11
        127.0.0.1:6379> get message
        "hello world"
        127.0.0.1:6379> 
        
      • 整数操作

        INCRBY key 步长
        
        DECRBY key 步长
        
        NCR key : +1操作
        DECR key : -1操作
        
        应用场景:
        微博粉丝增加或减少就可以使用
        
      • 浮点数操作

        incrbyfloat key increment
        
      • string 命令汇总

        # 字符串操作
        1、set key value
        2、setnx key value
        3、get key
        3、mset key1 value1 key2 value2 key3 value3
        4、mget key1 key2 ke
        y3
        5、set key value ex seconds
        6、strlen key 
        # 数字操作
        7、incrby key 步长
        8、decrby key 步长
        9、incr key
        10、decr key
        11、incrbyfloat key number
        # 设置过期时间的两种方式
        # 方式一
        1、set key value ex 3
        # 方式二
        1、set key value
        2、expire key 5 # 秒
        3、pexpire key 5 # 毫秒
        # 查看存活时间
        ttl key
        # 删除过期
        persist key
        
      • 通用命令汇总

        # 切换库
        select number(0-15)
        # 查看所有键
        keys * 
        # 键类型
        TYPE key
        # 键是否存在
        exists key
        # 删除键
        del key
        # 键重命名
        rename key newkey
        # 返回旧值并设置新值(如果键不存在,就创建并赋值)
        getset key value
        # 清除当前库中所有数据(慎用)
        flushdb
        # 清除所有库中所有数据(慎用)
        flushall
        
      • string 数据类型注意

        # key值取值原则
        1、key值不宜过长,消耗内存,且在数据中查找这类键值的计算成本高
        2、不宜过短,可读性较差
        # 值
        1、一个字符串类型的值最多能存储512M内容
        
    • 列表数据类型

      • 特点

        1、元素是字符串类型
        2、列表头尾增删快,中间增删慢,增删元素是常态
        3、元素可重复
        4、最多可包含2^32 -1个元素
        5、索引同python列表
        
      • 头尾压入元素(LPUSH | RPUSH)

        # LPUSH : Left
        # RPUSH : Right
        ['lucy','tom','10']
        
      • 查看|设置 列表元素

        查看(LRANGE)
        # lrange key start stop
        lrange mylist1 0 2   # 显示前3个元素
        lrange mylist1 0 -1  # 显示列表中所有元素
        
        获取指定位置元素(LINDEX)
        lindex key index
        
        设置指定位置元素的值(LSET)
        lset key index value
        
        获取列表长度(LLEN)
        llen key
        
      • 头尾弹出元素(LPOP | RPOP)

        LPOP key : 从列表头部弹出一个元素
        
        RPOP key : 从列表尾部弹出一个元素
        
        RPOPLPUSH source destination : 从一个列表尾部弹出元素压入到另一个列表头部
        rpoplpush mylist1 mylist2
        
      • 移除指定元素(LREM)

        LREM key count value
        count>0:表示从头部开始向表尾搜索,移除与value相等的元素,数量为count
        count<0:表示从尾部开始向表头搜索,移除与value相等的元素,数量为count
        count=0:移除表中所有与value相等的值
        
        示例:
        lrem mylist 0 tom
        lrem mylist 1 tom
        lrem mylist -2 tom
        
      • 去除指定范围外元素(LTRIM)

        LTRIM key start stop
        
        应用场景: 保存微博评论最后500条
        weibo:comments   [评论,评论,。。。。。,。。。。] 
        # LPUSH (考虑列表中元素顺序)
        LTRIM weibo:comments 0 499
        # RPUSH
        LRTIM weibo:comments -500 -1
        
      • 列表中插入值(LINSERT)(了解)

        LINSERT key BEFORE|AFTER value  new_value
        key和pivot不存在,不进行任何操作
        示例代码
        [1 2 3 4 5 2 ]
        LINSERT mylist after 2 8
        
      • 阻塞弹出(BLPOP | BRPOP)(重要)

        BLPOP key timeout
        
        BRPOP key timeout
        
        1、如果弹出的列表不存在或者为空,就会阻塞
        2、超时时间设置为0,就是永久阻塞,直到有数据可以弹出
        3、如果多个客户端阻塞再同一个列表上,使用First In First Service原则,先到先服务
        
        示例:
        brpop mylist 0 # 永久阻塞
        brpop mylist 3 # 超时时间3秒
        
      • 列表常用命令总结

        # 增
        1、LPUSH key value1 value2 
        2、RPUSH key value1 value2
        3、RPOPLPUSH source destination
        4、LINSERT key after|before value newvalue
        # 查
        5、LRANGE key start stop
        6、LLEN key
        # 删
        7、LPOP key
        8、RPOP key
        9、BLPOP key timeout
        10、BRPOP key timeout
        11、LREM key count value
        12、LTRIM key start stop # 微博评论500条
        # 改
        13、LSET key index newvalue
        
    • 位图操作

      • 定义

        1、位图不是真正的数据类型,它是定义在字符串类型中
        2、一个字符串类型的值最多能存储512M字节的内容,位上限:2^32
        # 1MB = 1024KB
        # 1KB = 1024Byte(字节)
        # 1Byte = 8bit(位)
        
      • 强势点

        可以实时的进行统计,极其节省空间。官方在模拟1亿2千8百万用户的模拟环境下,
        在一台MacBookPro上,典型的统计如“日用户数”的时间消耗小于50ms, 占用16MB内存
        
      • 常用命令

        # 设置某一位上的值(offset是偏移量,从0开始)
        setbit key offset value
        # 获取某一位上的值
        GETBIT key offset
        # 统计键所对应的值中有多少个 1 
        BITCOUNT key
        
      • 应用场景案例

        网站用户的上线次数统计(寻找活跃用户)
        用户名为key,上线的天作为offset,上线设置为1
        
        示例: 用户名为 user001 的用户,今年第1天上线,第30天上线
        
        SETBIT user001 0 1 
        SETBIT user001 29 1
        BITCOUNT user001
        
    • Hash散列数据类型

      • 定义

        1、由field和关联的value组成的键值对
        2、field和value是字符串类型
        3、一个hash中最多包含2^32-1个键值对
        
      • 优点

        1、节约内存空间
        2、每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等)
        3、键越多,redis数据库在储存附件管理信息方面耗费内存越多,花在管理数据库键上的CPU也会越多
        
      • 缺点(不适合hash情况)

        1、使用二进制位操作命令:SETBIT、GETBIT、BITCOUNT等,如果想使用这些操作,只能用字符串键
        2、使用过期键功能:键过期功能只能对键进行过期操作,而不能对散列的字段进行过期操作
        
      • 基本命令操作

        # 1、设置单个字段
        HSET key field value
        HSETNX key field value
        # 2、设置多个字段
        HMSET key field value field value
        # 3、返回字段field个数
        HLEN key
        # 4、判断字段是否存在(不存在返回0)
        HEXISTS key field
        # 5、返回字段值
        HGET key field
        # 6、返回多个字段值
        HMGET key field filed
        # 7、返回所有的键值对
        HGETALL key
        # 8、返回所有字段名
        HKEYS key
        # 9、返回所有值
        HVALS key
        # 10、删除指定字段
        HDEL key field field field
        # 11、在字段对应值上进行整数增量运算
        HINCRBY key field increment
        # 12、在字段对应值上进行浮点数增量运算
        HINCRBYFLOAT key field increment
        
      • 应用场景:微博好友关注

        1、用户ID为key,Field为好友ID,Value为关注时间
        	   key          field    value
            user:10000    user:606  20190520
        	              user:605  20190521
        2、用户维度统计
           统计数包括:关注数、粉丝数、喜欢商品数、发帖数
           用户为key,不同维度为field,value为统计数
           比如关注了5人
        	HSET user:10000 fans 5
        	HINCRBY user:10000 fans 1
        
    • 集合数据类型(set)

      • 特点

        1、无序、去重
        2、元素是字符串类型
        3、最多包含2^32-1个元素
        
      • 基本命令

        # 1、增加一个或者多个元素,自动去重
        SADD key member1 member2
        # 2、查看集合中所有元素
        SMEMBERS key
        # 3、删除一个或者多个元素,元素不存在自动忽略
        SREM key member1 member2
        # 3、随机弹出元素(默认弹出一个)
        SPOP key [count]
        # 4、元素是否存在
        SISMEMBER key member
        # 5、随机返回集合中指定个数的元素,默认为1个
        SRANDOMMEMBER key [count]
        # 6、返回集合中元素的个数,不会遍历整个集合,只是存储在键当中了
        SCARD key
        # 7、把元素从源集合移动到目标集合
        SMOVE source destination member
        # 8、差集(number1 1 2 3 number2 1 2 4)
        SDIFF key1 key2 
        # 9、差集保存到另一个集合中
        SDIFFSTORE destination key1 key2
        # 10、交集
        SINTER key1 key2
        SINTERSTORE destination key1 key2
        # 11、并集
        SUNION key1 key2
        SUNIONSTORE destination key1 key2
        
      • 应用场景: 新浪微博的共同关注

        需求: 当用户访问另一个用户的时候,会显示出两个用户共同关注过哪些相同的用户
        设计: 将每个用户关注的用户放在集合中,求交集即可
        实现:
        
        user001 = {'peiqi','qiaozhi','danni'}
        user002 = {'peiqi','qiaozhi','lingyang'}
        
        user001和user002的共同关注为:
        # SINTERSTORE user_all user001 user002
        # SINTER user001 user002
        
    • 有序集合 sortedset

      • 特点

        1、有序、去重
        2、元素是字符串类型
        3、每个元素都关联着一个浮点数分值(score),并按照分值从小到大的顺序排列集合中的元素(分值可以相同)
        4、最多包含2^32-1元素
        
      • 示例

        • 一个保存了水果价格的有序集合

        • 一个保存了员工薪水的有序集合

      • 增加

        zadd key score member
        # 在有序集合中添加一个成员
        zadd key score member
        # 查看指定区间元素(升序)
        zrange key start stop [withscores]
        # 查看指定区间元素(降序)
        ZREVRANGE key start stop [withscores]
        # 查看指定元素的分值
        ZSCORE key member
        # 返回指定区间元素
        # offset : 跳过多少个元素
        # count : 返回几个
        # 小括号 : 开区间  zrangebyscore salary (6000 (8000
        zrangebyscore key min max [withscores] [limit offset count]
        limit 2 3 # 显示第 3 4 5 三个元素
        # 删除成员
        zrem key member
        # 增加或者减少分值
        zincrby key increment member
        # 返回元素排名
        zrank key member
        # 返回元素逆序排名
        zrevrank key member
        # 删除指定区间内的元素
        zremrangebyscore key min max
        # 返回集合中元素个数
        zcard key
        # 返回指定范围中元素的个数
        zcount key min max
        zcount fruits 4 7 
        zcount fruits (4 7
        # 并集
        zunionstore destination numkeys key [weights 权重值] [AGGREGATE SUM|MIN|MAX]
        # zunionstore zset4 2 zset1 zset2 aggregate max
        # 交集:和并集类似,只取相同的元素
        ZINTERSTORE destination numkeys key1 key2 WEIGHTS weight AGGREGATE SUM|MIN|MAX
        
      • 应用场景1:网易云音乐排行榜

        1、每首歌的歌名作为元素(先不考虑重复)
        2、每首歌的播放次数作为分值
        3、使用ZREVRANGE来获取播放次数最多的歌曲
        
      • 应用场景2: 京东商品畅销榜

        # 第1天
        ZADD mobile-001 5000 'huawei' 4000 'oppo' 3000 'iphone'
        # 第2天
        ZADD mobile-002 5200 'huawei' 4300 'oppo' 3230 'iphone'
        # 第3天
        ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone'
        问题:如何获取三款手机的销量排名?
        # 
        1、ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone'
        2、ZUNIONSTORE mobile-001:003 mobile-001 mobile-002 mobile-003 AGGREGATE MAX
        

  • 与Python交互

    • 模块

      • Ubuntu

        sudo pip3 install redis
        
      • Windows

        python -m pip install redis
        
      • 使用流程

        import redis
        # 创建数据库连接对象
        r = redis.Redis(host='127.0.0.1',port=6379,db=0,password='123456')
        
      • Python操作字符串类型

        import redis
        
        r = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)
        
        r.set('mystring','python')
        # b'python'
        print(r.get('mystring'))
        # False
        print(r.setnx('mystring','socket'))
        # mset:参数为字典
        r.mset({
                  
                  'mystring2':'mysql','mystring3':'mongodb'})
        # mget:结果为一个列表
        print(r.mget('mystring','mystring2','mystring3'))
        # mystring长度:6
        print(r.strlen('mystring'))
        # 数字类型操作
        r.set('number',10)
        r.incrby('number',5)
        r.decrby('number',5)
        r.incr('number')
        r.decr('number')
        r.incrbyfloat('number',6.66)
        r.incrbyfloat('number',-6.66)
        # b'10'
        print(r.get('number'))
        
      • 案例1:网易音乐排行榜(有序集合)

        import redis
        
        r = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)
        
        r.zadd('ranking',{
                  
                  'song1':1,'song2':1,'song3':1,'song4':1})
        r.zadd('ranking',{
                  
                  'song5':1,'song6':1,'song7':1})
        r.zadd('ranking',{
                  
                  'song8':1,'song9':1})
        
        r.zincrby('ranking',50,'song3')
        r.zincrby('ranking',60,'song5')
        r.zincrby('ranking',80,'song7')
        # 获取前10名
        rlist = r.zrevrange('ranking',0,2,withscores=True)
        
        i = 1
        for r in rlist:
            print('第%d名:%s' % (i,r[0].decode()))
            i += 1
        
      • 案例2: 京东商品畅销榜

        import redis
        
        r = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)
        
        # 第1天
        day01_dict = {
                  
                  
            'huawei' : 5000,
            'oppo'   : 4000,
            'iphone' : 3000
        }
        # 第2天
        day02_dict = {
                  
                  
            'huawei' : 5200,
            'oppo'   : 4300,
            'iphone' : 3230
        }
        # 第3天
        day03_dict = {
                  
                  
            'huawei' : 5500,
            'oppo'   : 4660,
            'iphone' : 3580
        }
        r.zadd('mobile-day01',day01_dict)
        r.zadd('mobile-day02',day02_dict)
        r.zadd('mobile-day03',day03_dict)
        
        r.zunionstore('mobile-day01:03',('mobile-day01','mobile-day02','mobile-day03'),aggregate='max')
        rlist = r.zrevrange('mobile-day01:03',0,-1,withscores=True)
        
        i = 1
        for r in rlist:
            print('第{}名:{}'.format(i,r[0].decode()) )
        

end…

Guess you like

Origin blog.csdn.net/weixin_42218582/article/details/103083585