zoukankan      html  css  js  c++  java
  • redis.md

    redis学习

    Nosql

    数据访问量越来越大:

    1. 单机
    2. Memcached

    数据类型

    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379> keys *  # 查看所有键
    (empty array)
    127.0.0.1:6379> set age "敖德萨大"  # 设置值
    OK
    127.0.0.1:6379> keys * 
    1) "age"
    127.0.0.1:6379> keys age
    1) "age"
    127.0.0.1:6379> get age  # 获取值
    "\xe6\x95\x96\xe5\xbe\xb7\xe8\x90\xa8\xe5\xa4\xa7"
    127.0.0.1:6379> EXISTS age # 判断key是否存在
    (integer) 1
    127.0.0.1:6379> EXISTS agea
    (integer) 0
    127.0.0.1:6379> move age  # 语法错误,需要数据库
    (error) ERR wrong number of arguments for 'move' command
    127.0.0.1:6379> move age 1 # 移除库1中的age
    (integer) 1
    
    # 过期时间设置
    127.0.0.1:6379> set name "IOIOIO" 
    OK
    127.0.0.1:6379> keys name
    1) "name"
    127.0.0.1:6379> get name
    "IOIOIO"
    127.0.0.1:6379> EXPIRE name 10 # 设置过期时间
    (integer) 1
    127.0.0.1:6379> ttl name # 查看存活时间
    (integer) 6
    127.0.0.1:6379> ttl name
    (integer) 3
    127.0.0.1:6379> ttl name
    (integer) -2
    127.0.0.1:6379> ttl name
    (integer) -2
    127.0.0.1:6379> keys *
    (empty array)
    127.0.0.1:6379> get name
    (nil)
    
    # 查看类型
    127.0.0.1:6379> set age 12
    OK
    127.0.0.1:6379> type age
    string
    

    String

    场景:

    • string
    • 计数器
    • 对象缓存存储
    • cookie
    127.0.0.1:6379> set name "abcdefghijklmn"
    OK
    127.0.0.1:6379> append name " 123456" # 追加,如果key不存在则创建空并追加
    (integer) 21  # 返回append之后的长度
    127.0.0.1:6379> get name  
    "abcdefghijklmn 123456"
    127.0.0.1:6379> STRLEN name  # 获取长度
    (integer) 21
    
    # 加减
    127.0.0.1:6379> set views 0
    OK
    127.0.0.1:6379> type views
    string
    127.0.0.1:6379> type view # key不存在时类型为none
    none
    127.0.0.1:6379> incr views  # 加 1
    (integer) 1
    127.0.0.1:6379> type views
    string
    127.0.0.1:6379> get views
    "1"
    127.0.0.1:6379> DECR views # 减 1
    (integer) 0
    127.0.0.1:6379> get views
    "0"
    127.0.0.1:6379> INCRBY views 98 # 步长98自增
    (integer) 98
    127.0.0.1:6379> DECRBY views 9
    (integer) 89
    127.0.0.1:6379> APPEND views io9 # views == "9io9"
    (integer) 5
    127.0.0.1:6379> incr views # 自增错误,非整数
    (error) ERR value is not an integer or out of range
    
    # 获取字符串范围
    127.0.0.1:6379> set name "hello, world!"
    OK
    127.0.0.1:6379> GETRANGE name 0 -1  # -1 代表最后一位
    "hello, world!"
    127.0.0.1:6379> GETRANGE name 0 100 # 超过本身长度不报错
    "hello, world!"
    127.0.0.1:6379> GETRANGE name 0 3  # 一般获取
    "hell"
    127.0.0.1:6379> GETRANGE name 100 -1 # 返回空
    ""
    127.0.0.1:6379> GETRANGE name 100 9
    ""
    127.0.0.1:6379> GETRANGE name 100 900
    ""
    127.0.0.1:6379> GETRANGE name -1 0 
    ""
    127.0.0.1:6379> GETRANGE names 0 -1  # key不存在时返回“”
    ""
    
    # 指定范围替换
    127.0.0.1:6379> SETRANGE name 1 xx
    (integer) 13
    127.0.0.1:6379> get name
    "hxxlo, world!"
    
    # setex (set with expire) 设置值的同时过期时间
    # setnx (set if not exist) 不存在时才设置 
    127.0.0.1:6379> setex key3 30 "Wait ...." 
    OK
    127.0.0.1:6379> get key3
    "Wait ...."
    127.0.0.1:6379> ttl key3
    (integer) 18
    127.0.0.1:6379> setnx mykey "first" # 不存在,设置成功
    (integer) 1
    127.0.0.1:6379> setnx mykey "second" # 已存在,设置失败
    (integer) 0
    127.0.0.1:6379> get mykey
    "first"
    127.0.0.1:6379> get key3 # 不存在,返回nil
    (nil)
    
    # 批量设置
    127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 批量设置
    OK
    127.0.0.1:6379> mget k1 v1 k2 k3  #批量获取
    1) "v1"
    2) (nil)
    3) "v2"
    4) "v3"
    127.0.0.1:6379> msetnx k1 OP k9 v9 # 保证一致性,k1已存在,设置失败,k9不再进行设置
    (integer) 0
    127.0.0.1:6379> keys *
    1) "k1"
    2) "k3"
    3) "k2"
    4) "mykey"
    127.0.0.1:6379> get k9
    (nil)
    
    # 对象保存
    127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18
    OK
    127.0.0.1:6379> mget user:1:name user:1:age
    1) "zhangsan"
    2) "18"
    
    # getset,获取当前的值并设置新值
    127.0.0.1:6379> getset db redis
    (nil)
    127.0.0.1:6379> get db
    "redis"
    127.0.0.1:6379> getset db mysql
    "redis"
    

    List

    列表:存储是链表(双向?)

    |--------------------------------------|
    |   |---|   |---|     |---|            |
    | L | 1 |   | 2 |     | 3 |     .... R |
    |   |---|   |---|     |---|            | 
    |--------------------------------------|
    
    • 在两边操作,效率比在中间元素操作高
    • 消息队列(lpush, rpop) 栈(lpush,)
    # l --> list | left
    127.0.0.1:6379> lpush list one # 放入队列中
    (integer) 1
    127.0.0.1:6379> lpush list two  
    (integer) 2
    127.0.0.1:6379> lpush list three
    (integer) 3
    127.0.0.1:6379> LRANGE list 0 -1  # 获取指定范围,输出栈的形式
    1) "three"
    2) "two"
    3) "one"
    127.0.0.1:6379> LRANGE list 0 1
    1) "three"
    2) "two"
    # r --> right
    127.0.0.1:6379> rpush list right # 向右边(尾部)插入
    (integer) 4
    127.0.0.1:6379> LRANGE list 0 -1
    1) "three"
    2) "two"
    3) "one"
    4) "right"
    
    # lpop rpop
    127.0.0.1:6379> lpop list # 弹出最左边的元素
    "three"
    127.0.0.1:6379> LRANGE list 0 -1
    1) "two"
    2) "one"
    3) "right"
    127.0.0.1:6379> rpop list  # 弹出最右边的元素
    "right"
    127.0.0.1:6379> LRANGE list 0 -1
    1) "two"
    2) "one"
    127.0.0.1:6379> lindex list 1 # 通过下标获取 
    "one"
    127.0.0.1:6379> lindex list 0
    "two"
    127.0.0.1:6379> Llen list # 返回列表长度
    (integer) 2
    
    # 移除值
    127.0.0.1:6379> lrange list 0 -1
    1) "three"
    2) "three"
    3) "three"
    4) "two"
    5) "one"
    127.0.0.1:6379> lrem list 1 one  # 移除 1 个 one 元素
    (integer) 1
    127.0.0.1:6379> lrem list 2 three  # 移除 2 个 three 元素
    (integer) 2
    127.0.0.1:6379> lrem list 2 threeS
    (integer) 0
    127.0.0.1:6379> lrange list 0 -1
    1) "three"
    2) "two"
    
    # ltrim 截取 
    127.0.0.1:6379> LRANGE list 0 -1
    (empty array)
    127.0.0.1:6379> rpush list hello0
    (integer) 1
    127.0.0.1:6379> rpush list hello1
    (integer) 2
    127.0.0.1:6379> rpush list hello2
    (integer) 3
    127.0.0.1:6379> rpush list hello3
    (integer) 4
    127.0.0.1:6379> ltrim list 2 3 # ltrim key start end (会改变list!)
    OK
    127.0.0.1:6379> LRANGE list 0 -1
    1) "hello2"
    2) "hello3"
    
    # rpoplpush 右弹出并左压进其他列表 (弹出最后一个元素并放入其他列表的第一个元素)
    127.0.0.1:6379> LRANGE list 0 -1
    1) "hello2"
    2) "hello3"
    127.0.0.1:6379> rpoplpush list newlist # source desition
    "hello3"
    127.0.0.1:6379> LRANGE list 0 -1
    1) "hello2"
    127.0.0.1:6379> LRANGE newlist 0 -1
    1) "hello3"
    
    # 更新值 lset, 插入值 linsert
    127.0.0.1:6379> LRANGE list 0 -1
    1) "v0"
    2) "v1"
    3) "v2"
    4) "v3"
    5) "v3"
    127.0.0.1:6379> lset list 3 VALUE
    OK
    127.0.0.1:6379> LRANGE list 0 -1
    1) "v0"
    2) "v1"
    3) "v2"
    4) "VALUE"
    5) "v3"
    127.0.0.1:6379> lset list 5 VALUE # 超出范围
    (error) ERR index out of range
    127.0.0.1:6379> linsert list before v1 INSERT_V1 # 在值v之前插入
    (integer) 6
    127.0.0.1:6379> linsert list after v2 INSERT_V2  # 在值v2之后插入
    (integer) 7
    127.0.0.1:6379> LRANGE list 0 -1
    1) "v0"
    2) "INSERT_V1"
    3) "v1"
    4) "v2"
    5) "INSERT_V2"
    6) "VALUE"
    7) "v3"
    

    Set

    # sadd 添加  smembers 列出所有成员
    127.0.0.1:6379> sadd set hello
    (integer) 1
    127.0.0.1:6379> sadd set hello1
    (integer) 1
    127.0.0.1:6379> sadd set hello2
    (integer) 1
    127.0.0.1:6379> SMEMBERS set
    1) "hello2"
    2) "hello"
    3) "hello1"
    # sismember 判断是否存在某一元素
    127.0.0.1:6379> SISMEMBER set hello # 存在
    (integer) 1
    127.0.0.1:6379> SISMEMBER set hello12 # 不存在
    (integer) 0
    # scard 获取集合元素的个数
    127.0.0.1:6379> scard set
    (integer) 3
    # srem 移除元素
    127.0.0.1:6379> srem set
    (error) ERR wrong number of arguments for 'srem' command
    127.0.0.1:6379> srem set hello
    (integer) 1
    127.0.0.1:6379> SMEMBERS set
    1) "hello2"
    2) "hello1"
    # srandmember set [count] 随机抽取指定个数的元素
    # spop set 随机删除元素
    # smove source destition value 移动指定元素
    # sdiff 差集
    # sinter  交集
    # sunion 并集 
    

    Hash

    # hset hget hgetall
    127.0.0.1:6379> hset hash k1 v1 k2 v2 k3 v3
    (integer) 3
    127.0.0.1:6379> hget hash k1
    "v1"
    127.0.0.1:6379> hgetall hash
    1) "k1"
    2) "v1"
    3) "k2"
    4) "v2"
    5) "k3"
    6) "v3"
    # hdel 删除
    127.0.0.1:6379> hdel hash k1
    (integer) 1
    # hlen 长度
    127.0.0.1:6379> hgetall hash
    1) "k2"
    2) "v2"
    3) "k3"
    4) "v3"
    127.0.0.1:6379> HLEN hash
    (integer) 2
    # hexists 是否存在
    127.0.0.1:6379> HEXISTS hash k1 # 不存在
    (integer) 0
    127.0.0.1:6379> HEXISTS hash k2 # 存在
    (integer) 1
    # hkeys 只获取key, hvals 只获取value
    127.0.0.1:6379> hkeys hash
    1) "k2"
    2) "k3"
    127.0.0.1:6379> HVALS hash
    1) "v2"
    2) "v3"
    # hincrby hsetnx
    

    Zset

    有序集合

    # zadd zrange
    127.0.0.1:6379> zadd myset 1 one
    (integer) 1
    127.0.0.1:6379> zadd myset 2 two
    (integer) 1
    127.0.0.1:6379> zadd myset 3 three
    (integer) 1
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "one"
    2) "two"
    3) "three"
    # zrangebyscore 排序
    127.0.0.1:6379> zrangebyscore myset -inf +inf
    1) "one"
    2) "two"
    3) "three"
    # 同时输出score
    127.0.0.1:6379> zrangebyscore myset -inf 10 withscores
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    # zrem 移除
    127.0.0.1:6379> zrangebyscore myset -inf 10 withscores
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    # zcard 查看数量
    # zcount 获取指定区间的元素数量
    127.0.0.1:6379> zcount myset 0 9
    (integer) 2
    
    

    Geospatial

    地理位置

    底层是zset

    # geoadd 添加
    127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
    (integer) 1
    127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
    (integer) 1
    127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing
    (integer) 1
    # geopos 获取
    127.0.0.1:6379> geopos china:city beijing
    1) 1) "116.39999896287918091"
       2) "39.90000009167092543"
    # geodist 计算直线距离
    127.0.0.1:6379> geodist china:city beijing shanghai m
    "1067378.7564"
    127.0.0.1:6379> geodist china:city beijing shanghai km
    "1067.3788"
    # georadious 计算给定坐标给定半径内的key
    127.0.0.1:6379> georadius china:city 110 30 1000 km
    1) "chongqing"
    # 同时限制数量,给出坐标和距离
    127.0.0.1:6379> georadius china:city 110 30 2000 km withdist withcoord count 1
    1) 1) "chongqing"
       2) "341.9374"
       3) 1) "106.49999767541885376"
          2) "29.52999957900659211"
    # groradiousmember 找出给定城市给定距离的城市
    127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1300 km
    1) "shanghai"
    2) "beijing"
    # geohash 返回地址的hash,失去精度但仍指向同一区域
    127.0.0.1:6379> geohash china:city beijing
    1) "wx4fbxxfke0"
    # zrem 移除 zrange 查看
    127.0.0.1:6379> ZREM china:city beijing
    (integer) 1
    127.0.0.1:6379> ZRANGE china:city 0 -1
    1) "chongqing"
    2) "shanghai"
    

    Hyperloglog

    基数:两个集合不重复的元素,可以有误差(0.81%的误差)

    优点:

    • 占用内存固定,264不同的元素,需要12KB

    网页的访问数:传统方式使用set保存用户ID来避免同一用户访问造成的多次计数。

    # pfadd 添加
    127.0.0.1:6379> pfadd key  1 2 3 4 5 6 7 8 9 0
    (integer) 1
    127.0.0.1:6379> pfadd key1 ! 2 3 $ 5 6 & 8 9  )
    (integer) 1
    # pfcount 计算基数
    127.0.0.1:6379> pfcount key key1
    (integer) 14
    127.0.0.1:6379> pfcount key
    (integer) 10
    127.0.0.1:6379> pfcount key1
    (integer) 10
    # pmerge 合并key和key1到key3
    127.0.0.1:6379> PFMERGE key3 key key1
    OK
    127.0.0.1:6379> pfcount key3
    (integer) 14
    

    BitMap

    位存储

    统计用户活跃|不活跃、登录|未登录、打卡|未打卡……只有两个状态的,可以使用Bitmaps!

    Bitmaps位图,数据结构,操作二进制位进行记录

    # setbit 设置位
    127.0.0.1:6379> setbit sign 5 1 # 第5天的状态
    (integer) 0
    127.0.0.1:6379> setbit sign 6 0 # 第6天的状态
    (integer) 0
    127.0.0.1:6379> setbit sign 7 1 # 第7天的状态
    (integer) 0
    # getbit 获取
    127.0.0.1:6379> setbit sign 1 0
    (integer) 1
    127.0.0.1:6379> getbit sign 1
    (integer) 0
    # bitcount 计数
    127.0.0.1:6379> bitcount sign
    (integer) 7
    127.0.0.1:6379> bitcount sign 0 -1
    (integer) 7
    
    

    事务

    Redis单条命令保证原子性,但事务不保证原子性!

    redis的事务:

    • 开启事务(multi)
    • 命令入队()
    • 执行事务(exec)

    Redis可以实现乐观锁。

    # multi   exec
    127.0.0.1:6379> multi # 开启事务
    OK
    127.0.0.1:6379(TX)> set k1 v1
    QUEUED
    127.0.0.1:6379(TX)> set k2 v2
    QUEUED
    127.0.0.1:6379(TX)> get v3
    QUEUED
    127.0.0.1:6379(TX)> set v3 V3
    QUEUED
    127.0.0.1:6379(TX)> exec  # 执行
    1) OK
    2) OK
    3) (nil)
    4) OK
    # discard 放弃事务
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> set key6 v6
    QUEUED
    127.0.0.1:6379(TX)> discard
    OK
    127.0.0.1:6379> exec
    (error) ERR EXEC without MULTI
    

    错误处理

    • 代码异常:所有事务不执行
    • 运行异常: 其他命令正常执行,错误直接忽略

    乐观锁

    • 悲观锁:认为什么时候都有问题,无论做什么都会加锁
    • 乐观锁: 认为什么都没问题, 不会上锁!更新数据时去判断,在此期间是否有人修改过此数据。
      • 获取version
      • 更新时比较version
    # 正常执行成功
    127.0.0.1:6379> set money 100
    OK
    127.0.0.1:6379> set out 0
    OK
    127.0.0.1:6379> watch money # 监视money对象
    OK
    127.0.0.1:6379> mutil
    (error) ERR unknown command `mutil`, with args beginning with:
    127.0.0.1:6379> multi  # 事务正常结束,期间数据未被改动,执行成功!
    OK
    127.0.0.1:6379(TX)> decrby money 20
    QUEUED
    127.0.0.1:6379(TX)> INCRBY out 20
    QUEUED
    127.0.0.1:6379(TX)> exec
    1) (integer) 80
    2) (integer) 20
    
    # 多线程执行失败
    
    # 连接1
    127.0.0.1:6379> set money 100
    OK
    127.0.0.1:6379> watch money  # 进行监视(加锁)
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> INCRBY money 20  
    QUEUED
    127.0.0.1:6379(TX)> exec # 先去执行连接B
    (nil)                    # 事务执行失败
    127.0.0.1:6379> unwatch # 取消监视
    OK
    127.0.0.1:6379> watch money # 监视新值
    OK
    # ………………………继续上面的操作(自弦索)
    
    # 连接B
    127.0.0.1:6379> get money
    "100"
    127.0.0.1:6379> DECRBY money 90
    (integer) 10
    
    

    Jedis

    Java操作Redis

    Jedis方法与redis命令一致

    public static void main(String[] args) {
        // 连接Jedis
            Jedis jedis = new Jedis();
            // Jedis 即所有指令
            System.out.println(jedis.ping("fdsfds"));
        }
    }
    

    SpringBoot整合

    Spring-Data

  • 相关阅读:
    《软件性能测试与LoadRunner实战教程》新书上市
    《你必须掌握的Entity Framework 6.x与Core 2.0》正式出版感想
    《你必须掌握的Entity Framework 6.x与Core 2.0》书籍出版
    别跟我谈EF抵抗并发,敢问你到底会不会用EntityFramework
    EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)
    已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍
    WebAPi之SelfHost自创建证书启动Https疑难解惑及无法正确返回结果
    Web APi之认证(Authentication)两种实现方式【二】(十三)
    读懂操作系统之虚拟内存TLB与缓存(cache)关系篇(四)
    读懂操作系统之缓存原理(cache)(三)
  • 原文地址:https://www.cnblogs.com/nsfoxer/p/15588075.html
Copyright © 2011-2022 走看看