美文网首页
redis五大数据类型 hdx

redis五大数据类型 hdx

作者: 黄殿玺 | 来源:发表于2020-12-12 22:54 被阅读0次

    一、5大基础类型

    1. 基本命令

    keys *          #查看当前库所有k
    set k v         #设置k, v
    get k           #获取k
    expire k 10     #设置key过期时间  单位秒
    ttl k           #查看k的剩余时间
    select 0        #切换数据库 0/16 默认16个库 配置文件中配置
    flushdb         #清空当前库k
    flushall        #清空所有库k
    move k          #移除k
    exists k,k1     #查询k是否存在
    type k          #查询k对应的v存储类型
    

    2. String类型

    append k v          #追加字符串,如果k不存在就相当添加
    strlen k            #获取字符串长度
    -----------------------------
    incr k              #原子加1
    decr k              #原子减1
    incrby k 10         #原子加10  10是步长 可用在浏览量
    decrby k 10         #原子减10  10是步长   
    -----------------------------
    getrange k 0 3      #截取字符串 从0位置-3位置 4个字符串
    getrange k 0 -1     #去字符串所有内容
    -----------------------------
    setrange k 1 xxx    #从下标位1开始替换后面的内容
    -----------------------------
    setex k v 60        #设置k,v,过期时间
    -----------------------------
    setnx k v           #k不存在再设置值(常在分布式锁中使用)
    -----------------------------
    mset k1 v1 k2 v2 k3 v3  #批量设置k,v
    msetnx k1 v1 k4 v4      #存在的key,值就不设置了
    mget k1 k2 k3           #获取多个key值
    -----------------------------
    getset k v              #先获取在设置, CAS 原子操作
    e.g
    114.116.230.154:6397> getset db redis
    (nil)
    114.116.230.154:6397> get db
    "redis"
    114.116.230.154:6397> getset db mongodb
    "redis"
    114.116.230.154:6397> get db
    "mongodb"
    

    3. List

    list 可以用来实现队列、栈,所有的命令都是以==L==开头。

    #从左向右添加数据,如果集合不存在创建集合
    114.116.230.154:6397> lpush list one    #lpush:从左向右添加,后添加的总是在头部0的位置(栈)
    (integer) 1
    114.116.230.154:6397> lpush list two
    (integer) 2
    114.116.230.154:6397> lpush list three
    (integer) 3
    114.116.230.154:6397> lrange list 0 -1  #获取list中的所有值
    1) "three"
    2) "two"
    3) "one"
    114.116.230.154:6397> lrange list 0 1   #获取list中的区间值,如果获取第一个值 lrange list 0 0
    1) "three"
    2) "two"
    ------------------------------------------
    #从右向左添加数据,如集合不存在添加集合
    114.116.230.154:6397> rpush list right  #rpush:从右向左添加
    (integer) 4
    114.116.230.154:6397> lrange list 0 -1
    1) "three"
    2) "two"
    3) "one"
    4) "right"
    ------------------------------------------
    #从左边或者右边弹出元素
    114.116.230.154:6397> lrange list  0 -1
    1) "three"
    2) "two"
    3) "one"
    4) "right"
    114.116.230.154:6397> lpop list     #弹出左边第一个元素,并移除
    "three"
    114.116.230.154:6397> lrange list 0 -1
    1) "two"
    2) "one"
    3) "right"
    114.116.230.154:6397> rpop list     #弹出右边第一个元素,并移除
    "right"
    114.116.230.154:6397> lrange list 0 -1
    1) "two"
    2) "one"
    # lpush + lpop(栈),lpush + rpop(队列)
    -----------------------------------------
    #获取集合中指定下标元素
    114.116.230.154:6397> lrange list 0 -1  #展示list集合中所有元素
    1) "two"
    2) "one"
    114.116.230.154:6397> lindex list 0     #根据list集合下标获取集合元素
    "two"
    114.116.230.154:6397> lindex list 1
    "one"
    -----------------------------------------
    #获取集合长度
    114.116.230.154:6397> lrange list 0 -1
    1) "two"
    2) "one"
    114.116.230.154:6397> llen list         #获取list集合长度
    (integer) 2
    -----------------------------------------
    #移除集合中的指定元素值,并指定移除几个
    114.116.230.154:6397> lpush list one two three three    #从左向右添加值
    (integer) 4
    114.116.230.154:6397> lrange list 0 -1
    1) "three"
    2) "three"
    3) "two"
    4) "one"
    114.116.230.154:6397> lrem list 1 one   #移除指定值one,并移除1个
    (integer) 1
    114.116.230.154:6397> lrange list 0 -1
    1) "three"
    2) "three"
    3) "two"
    (0.53s)
    114.116.230.154:6397> lrem list 3 three #移除指定值three,并移除3个,但实际就2个所以都移除了。
    (integer) 2
    114.116.230.154:6397> lrange list 0 -1
    1) "two"
    ---------------------------------------
    #结合修剪,截取指定下标 n~m 的元素包含n,m的内容
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h5"
    2) "h4"
    3) "h3"
    4) "h2"
    5) "h1"
    114.116.230.154:6397> ltrim mylist 1 3  #ltrim:集合修剪操作,只保留下标1~3的元素
    OK
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h4"
    2) "h3"
    3) "h2"
    ---------------------------------------
    #将一个集合的最后一个元素pop,push到另一个集合中
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h6"
    2) "h5"
    3) "h4"
    4) "h3"
    5) "h2"
    114.116.230.154:6397> rpoplpush mylist newlist #从mylist最后一个元素移除,到新列表newlist
    "h2"
    114.116.230.154:6397> lrange newlist 0 -1
    1) "h2"
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h6"
    2) "h5"
    3) "h4"
    4) "h3"
    ---------------------------------------
    #指定下标赋值
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h6"
    2) "h5"
    3) "h4"
    4) "h3"
    114.116.230.154:6397> lset list 0 hdx   #指定下标赋值list不存在报错,所以先lpush或rpush
    (error) ERR no such key
    114.116.230.154:6397> lset mylist 1 h7  #向mylist集合的下标 1 处赋值 h7, 如下标不存在也会报错
    OK
    114.116.230.154:6397> lrange mylist 0 -1    #结果原下标 1 处的 h5 被覆盖
    1) "h6"
    2) "h7"
    3) "h4"
    4) "h3"
    ---------------------------------------
    #指定内容元素前or后插入新元素
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h6"
    2) "h7"
    3) "h4"
    4) "h3"
    114.116.230.154:6397> linsert mylist before h7 hdx  #向mylist集合中h7元素前面插入hdx元素
    (integer) 5
    114.116.230.154:6397> lrange mylist 0 -1
    1) "h6"
    2) "hdx"
    3) "h7"
    4) "h4"
    5) "h3"
    # 操作类似一个连表 [before] Node [after] 
    

    小结

    底层实现相当一个连表,比如lpush是向头节点插入数据,rpush是向尾节点插入数据。可以向某个具体节点插入数据 比如 linsert。

    可用用作队列,栈

    4. set

    set值是不能重复的,set的命令都是==S==开头

    #set的基本操作
    114.116.230.154:6397> sadd myset hello  #向myset集合中set值
    (integer) 1
    114.116.230.154:6397> sadd myset hdx
    (integer) 1
    114.116.230.154:6397> smembers myset    #展示myset集合中所有值
    1) "hdx"
    2) "hello"
    114.116.230.154:6397> sismember myset hdx   #查询某个值(hdx),是否存在集合中,存在返回1
    (integer) 1
    ---------------------------------------
    #获取set集合元素个数
    114.116.230.154:6397> smembers myset
    1) "hdx"
    2) "hello"
    114.116.230.154:6397> scard myset   #查看set集合元素个数
    (integer) 2
    ---------------------------------------
    #移除set集合元素
    114.116.230.154:6397> smembers myset    #展示set集合中的元素[hdx, hello]
    1) "hdx"
    2) "hello"
    114.116.230.154:6397> srem myset hdx    #移除set集合中的hdx元素
    (integer) 1
    114.116.230.154:6397> scard myset   #查询set集合中元素个数
    (integer) 1
    114.116.230.154:6397> smembers myset    #展示set集合中全部元素,只剩下hello
    1) "hello"
    ----------------------------------------
    #从set集合中随机获取指定个数元素
    114.116.230.154:6397> sadd myset a b c d e f g  #向set集合中添加7个元素
    (integer) 7
    114.116.230.154:6397> smembers myset    #展示set集合中所用元素
    1) "d"
    2) "c"
    3) "a"
    4) "g"
    5) "f"
    6) "e"
    7) "b"
    114.116.230.154:6397> srandmember myset 1   #随机获取 1 个元素
    1) "b"
    114.116.230.154:6397> srandmember myset 2   #随机获取 2 个元素
    1) "a"
    2) "g"
    
    #实现抽奖需求
    ----------------------------------------
    #将一个元素从一个集合移动到另一个集合
    114.116.230.154:6397> smembers myset
    1) "a"
    2) "g"
    3) "f"
    4) "c"
    5) "d"
    6) "e"
    7) "b"
    114.116.230.154:6397> smove myset newset a  #将myset集合中的a元素移动到newset集合中
    (integer) 1
    114.116.230.154:6397> smembers newset
    1) "a"
    114.116.230.154:6397> smembers myset
    1) "g"
    2) "f"
    3) "c"
    4) "d"
    5) "e"
    6) "b"
    ---------------------------------------
    #差集
    #交集
    #并集
    
    #差集
    114.116.230.154:6397> smembers myset    #myset集合元素
    1) "g"
    2) "f"
    3) "c"
    4) "d"
    5) "e"
    6) "b"
    114.116.230.154:6397> smembers newset   #newset集合元素
    1) "a"
    2) "x"
    3) "y"
    4) "b"
    5) "z"
    114.116.230.154:6397> sdiff myset newset  #myset与newset的差集(myset中哪些元素是newset没有的,比如 b元素 )
    1) "f"
    2) "g"
    3) "d"
    4) "c"
    5) "e"
    
    114.116.230.154:6397> sdiff newset myset  #newset与myset的差集(newset中哪些元素是myset中没有的,比如 b元素)
    1) "y"
    2) "x"
    3) "a"
    4) "z"
    #根据 myset,newset的顺序不同,结果集也不同。
    -----------------------------
    #交集
    114.116.230.154:6397> smembers myset
    1) "g"
    2) "f"
    3) "c"
    4) "d"
    5) "e"
    6) "b"
    114.116.230.154:6397> smembers newset
    1) "a"
    2) "x"
    3) "y"
    4) "b"
    5) "z"
    114.116.230.154:6397> sinter myset newset   #myset与newset的交集 b
    1) "b"
    114.116.230.154:6397> sinter newset myset   #newset与myset的交集 b 
    1) "b"
    #找出两个集合共有的元素
    -----------------------------
    #并集
    114.116.230.154:6397> smembers myset
    1) "g"
    2) "f"
    3) "c"
    4) "d"
    5) "e"
    6) "b"
    114.116.230.154:6397> smembers newset
    1) "a"
    2) "x"
    3) "y"
    4) "b"
    5) "z"
    114.116.230.154:6397> SUNION myset newset   #myset 与newset的并集
     1) "c"
     2) "d"
     3) "e"
     4) "b"
     5) "a"
     6) "f"
     7) "g"
     8) "y"
     9) "x"
    10) "z"
    #相当两个集合元素去重
    

    5. hash

    String数据类型是key:value

    hash数据类型是 key : (k:v),也可以理解成一对对象里面有多个属性。hash命令是以==h==开头。

    #hash 的形式
    114.116.230.154:6397> hset myhash filed1 hdx    #向myhash中设置一个键值对 k是field1,v是hdx
    (integer) 1
    114.116.230.154:6397> hget myhash filed1    #获取myhash中field1属性的值
    "hdx"
    114.116.230.154:6397> hmset myhash field1 hello field2 world #hmset向myhash中设置多个键值
    OK
    114.116.230.154:6397> hmget myhash field1 field2 #hmget 通过多个键从myhash中取出多个值
    1) "hello"
    2) "world"
    114.116.230.154:6397> hgetall myhash    #取出myhash的所有键和值
    1) "filed1" #键
    2) "hdx"    #值
    3) "field1" #键
    4) "hello"  #值
    5) "field2" #键
    6) "world"  #值
    114.116.230.154:6397> hkeys myhash  #获取myhahs中所有的key
    1) "filed1"
    2) "field2"
    114.116.230.154:6397> hvals myhash  #获取myhash中所有的value
    1) "hdx"
    2) "world"
    -----------------------------------
    114.116.230.154:6397> hgetall myhash
    1) "filed1" #键
    2) "hdx"    #值
    3) "field2" #键
    4) "world"  #值
    114.116.230.154:6397> hlen myhash   #获取myhash中的长度,结果证明是键值对的个数。
    (integer) 2
    -----------------------------------
    114.116.230.154:6397> hgetall myhash
    1) "filed1"
    2) "hdx"
    3) "field2"
    4) "world"
    114.116.230.154:6397> hexists myhash field2 #判断 myhash中field2属性是否存在
    (integer) 1
    -----------------------------------
    114.116.230.154:6397> hset myhash field3 5  
    (integer) 1
    114.116.230.154:6397> hincrby myhahs field3 1   #field3属性自增 1
    (integer) 1
    114.116.230.154:6397> hincrby myhash field3 -1  #field3属性自减 1
    (integer) 4
    

    hash数据类型可以用于对象的存储,而string只适合简单的字符串存储。

    6. zset

    zset 命令与set类似,zset命令以==z==开头,zset是有序的集合,只支持最小值到最大值排序。

    114.116.230.154:6397> zadd salary 500 hdx
    (integer) 1
    114.116.230.154:6397> zadd salary 1500 haha
    (integer) 1
    114.116.230.154:6397> zadd salary 2500 sanmao
    (integer) 1
    114.116.230.154:6397> zrangebyscore salary -inf +inf
    1) "hdx"
    2) "haha"
    3) "sanmao"
    114.116.230.154:6397> zrangebyscore salary +inf -inf    #不支持
    (empty list or set)
    ----------------------------------------
    114.116.230.154:6397> zrange salary 0 -1    #查询所有key
    1) "hdx"
    2) "haha"
    3) "sanmao"
    114.116.230.154:6397> zrem salary sanmao    #移除sanmao元素
    (integer) 1
    114.116.230.154:6397> zrange salary 0 -1
    1) "hdx"
    2) "haha"
    ----------------------------------------
    114.116.230.154:6397> zcard salary      #查看个数
    (integer) 2
    

    二、3大特殊类型

    1. geospatial 地理空间

    朋友定位,附近的人,打车

    #添加城市经纬度 前面是精度[-180~180] 纬度[-85~85]
    114.116.230.154:6397> geoadd china:city 116.40 39.91 beijing
    (integer) 1
    114.116.230.154:6397> geoadd china:city 121.47 31.23 shanghai
    (integer) 1
    114.116.230.154:6397> geoadd china:city 106.50 29.53 chongqing
    (integer) 1
    114.116.230.154:6397> geoadd china:city 114.05 22.52 shenzhen
    (integer) 1
    114.116.230.154:6397> geoadd china:city 120.16 30.24 hangzhou
    (integer) 1
    114.116.230.154:6397> geoadd china:city 108.96 34.26 xian
    (integer) 1
    ---------------------------------
    #geopos 获取城市北京经纬度
    114.116.230.154:6397> geopos china:city beijing 
    1) "116.39999896287918"
    2) "39.909999566644508"
    ---------------------------------
    #geopos两个城市之间的直线距离
    114.116.230.154:6397> geopos china:city beijing
    1) 1) "116.39999896287918"
       2) "39.909999566644508"
    114.116.230.154:6397> geodist china:city beijing shanghai
    "1068370.2525"
    (1.72s)
    114.116.230.154:6397> geodist china:city beijing shanghai km
    "1068.3703"
    ---------------------------------
    #georadius附近的人,给出一个精度查询半径之内的值
    114.116.230.154:6397> georadius china:city 110 30 500 km
    1) "chongqing"
    2) "xian"
    #精度110纬度30 半径500千米以内的城市
    -----------------
    #精度110纬度30 半径500千米以内的城市,并显示直线距离withdist,经纬度withcoord,查询个数count
    114.116.230.154:6397> georadius china:city 110 30 500 km withcoord withdist count 1
    1) 1) "chongqing"
       2) "341.9374"
       3) 1) "106.49999767541885"
          2) "29.529999579006592"
    ------------------
    #查询某个城市(key)的半径400千米的城市
    114.116.230.154:6397> georadiusbymember china:city hangzhou 400 km
    1) "hangzhou"
    2) "shanghai"
    ------------------
    #geospatial底层是通过zset实现的,所以移除元素可以是用zrem
    114.116.230.154:6397> zrange china:city 0 -1
    1) "chongqing"
    2) "xian"
    3) "shenzhen"
    4) "hangzhou"
    5) "shanghai"
    6) "beijing"
    114.116.230.154:6397> zrem china:city xian
    (integer) 1
    114.116.230.154:6397> zrange china:city 0 -1
    1) "chongqing"
    2) "shenzhen"
    3) "hangzhou"
    4) "shanghai"
    5) "beijing"
    

    2. hyperloglog

    是什么?是两个set集合去重合并返回元素数量。官方0.81%错误率,如果允许误差建议使用,效率高节省空间。如果不允许误差那么不建议使用。

    114.116.230.154:6397> pfadd mykey a b c d e f g h i j   #添加不可重复的元素集合
    (integer) 1
    114.116.230.154:6397> pfcount mykey #获取元素数量
    (integer) 10
    114.116.230.154:6397> pfadd mykey2 i j z x c v b n m
    (integer) 1
    114.116.230.154:6397> pfcount mykey
    (integer) 10
    114.116.230.154:6397> pfmerge mykey3 mykey mykey2   #合并mykye和mykey2元素,结果存到mykey3中
    OK
    114.116.230.154:6397> pfcount mykey3    #mykey3数量15,将两个集合去重合并统计数值
    (integer) 15
    

    3. bitmaps

    位存储,记录0,1状态

    114.116.230.154:6397> setbit sign 0 1   #
    (integer) 0
    114.116.230.154:6397> setbit sign 1 0
    (integer) 0
    114.116.230.154:6397> setbit sign 2 0
    (integer) 0
    114.116.230.154:6397> setbit sign 3 1
    (integer) 0
    114.116.230.154:6397> setbit sign 4 1
    (integer) 0
    114.116.230.154:6397> setbit sign 5 0
    (integer) 0
    114.116.230.154:6397> setbit sign 6 0
    (integer) 0
    114.116.230.154:6397> getbit sign 3     #获取到sign里面3 的状态
    (integer) 1
    114.116.230.154:6397> getbit sign 6     #获取到sign里面6 的状态
    (integer) 0
    114.116.230.154:6397> bitcount sign     #获取到sign里面状态为1的个数
    (integer) 3
    

    三、事务

    1.redis事务特性

    redis的事务是不保证原子性的(redis单条命令是保证原子性的)

    redis 事务没有隔离级别概念

    redis事务的特性:一次性、顺序性、排他性

    redis事务:

    开启事务(multi) -> 命令入队(...) -> 执行事务(exec)

    2.redis事务基本操作

    #正常开启事务执行事务
    114.116.230.154:6397> multi     #开启事务
    OK
    114.116.230.154:6397> set k1 v1
    QUEUED
    114.116.230.154:6397> set k2 v2
    QUEUED
    114.116.230.154:6397> get k2
    QUEUED
    114.116.230.154:6397> set k3 v3
    QUEUED
    114.116.230.154:6397> exec      #执行队列,并结束事务
    1) OK
    2) OK
    3) "v2"
    4) OK
    -----------------------
    114.116.230.154:6397> multi
    OK
    114.116.230.154:6397> set k1 v1
    QUEUED
    114.116.230.154:6397> set k2 v2
    QUEUED
    114.116.230.154:6397> set k4 v4
    QUEUED
    114.116.230.154:6397> discard   #取消事务,入队的命令都不会执行
    OK
    114.116.230.154:6397> get k4
    (nil)
    

    3.事务错误异常情况

    类比编译时异常:就是语法或命令错误导致的无法编译或执行,这类的异常在redis事务中是不会被执行的。

    114.116.230.154:6397> multi
    OK
    114.116.230.154:6397> set k1 v1
    QUEUED
    114.116.230.154:6397> set k2 v2
    QUEUED
    114.116.230.154:6397> set k3 v3
    QUEUED
    114.116.230.154:6397> getset k3
    (error) ERR wrong number of arguments for 'getset' command
    114.116.230.154:6397> set k4 v4
    QUEUED
    114.116.230.154:6397> set k5 v5
    QUEUED
    114.116.230.154:6397> exec
    (error) EXECABORT Transaction discarded because of previous errors.
    

    运行时异常:编译器在编译的时候无法发现错误,只有在程序运行过程中产生的错误。这类错误redis事务中是会被执行的。

    114.116.230.154:6397> multi
    OK
    114.116.230.154:6397> set k1 v1
    QUEUED
    114.116.230.154:6397> incr k1
    QUEUED
    114.116.230.154:6397> set k2 v2
    QUEUED
    114.116.230.154:6397> get k2
    QUEUED
    114.116.230.154:6397> exec
    1) OK
    2) (error) ERR value is not an integer or out of range
    3) OK
    4) "v2"
    114.116.230.154:6397> get k1
    "v1"
    114.116.230.154:6397> get k2
    "v2"
    

    4.事务监控

    监控:watch -- 乐观锁

    #正常执成功,事务正常结束,事务期间没有发生任何错误
    114.116.230.154:6397> set money 100
    OK
    114.116.230.154:6397> set out 0
    OK
    114.116.230.154:6397> watch money   #监视money值(乐观锁)
    OK
    114.116.230.154:6397> multi
    OK
    114.116.230.154:6397> decrby money 20
    QUEUED
    114.116.230.154:6397> incrby out 20
    QUEUED
    114.116.230.154:6397> exec
    1) (integer) 80
    2) (integer) 20
    

    多线程演示 watch

    #第一个线程操作
    114.116.230.154:6397> watch money   #监视money
    OK
    114.116.230.154:6397> multi #开启事务
    OK
    114.116.230.154:6397> decrby money 20
    QUEUED
    114.116.230.154:6397> incrby out 20
    QUEUED
    
    #第二个线程操作
    114.116.230.154:6397> decrby money 10   #减掉10块
    (integer) 70
    
    #第一个线程操作
    114.116.230.154:6397> exec  #第一个线程执行事务不成功
    (nil)
    
    #第一线程操作失败之后可以继续操作
    114.116.230.154:6397> unwatch   #接触监控
    OK
    114.116.230.154:6397> watch money   #重新获取监控
    OK
    114.116.230.154:6397> multi     #开启事务继续执行后续命令
    OK
    114.116.230.154:6397> decrby mone 20
    QUEUED
    114.116.230.154:6397> incrby out 20
    QUEUED
    114.116.230.154:6397> exec
    1) (integer) -20
    2) (integer) 40
    

    监控总结:money值通过 watch监视,如果在一个线程事务中正在执行还未提交,那么被监视的对象被另外一个线程修改了,再提交事务的时候会失败。这种机制符合乐观锁机制,认为什么时候值都不会被改变,之后在提交事务的时候去判断值是否与之前一致,一致成功反之失败。经典cas原理。

    如果是悲观锁:那么就是money这个值认为什么时候都有可能被修改,加锁之后只有当前加锁线程可以操作money。其他线程只有等待money锁释放后才能操作。

    所以在上面的例子中redis的监控(watch)机制显然是乐观锁机制。

    四、jedis

    p23

    相关文章

      网友评论

          本文标题:redis五大数据类型 hdx

          本文链接:https://www.haomeiwen.com/subject/ijzygktx.html