Redis(一)——String和底层数据结构实现

一、String

redis使用自己构建的名为简单动态字符串(SDS)的抽象类型作为默认字符串表示。

数据结构为:

struct sdshdr{
    int len;//buf数组已使用的字节,即SDS保存的字符串长度
    int free;//未使用的字节长度
    char buf[];//保存字符串的字节数组
}

如要保存redis这几个字符,则其SDS结构为:

buf[]:  'r','e','d','i','s','\0'
 len=5;
 free=0;

SDS像C的字符串一样最后保存一个额外的空字符。

1.1 SDS特性

  1. 常数复杂度获取字符串长度

    因为使用len记录了自身的长度,可以不像C字符串一样从头遍历进行计数获取。

  2. 避免缓冲区溢出

    SDS在需要修改时,会先检查空间是否满足大小,如果不满足,则先扩展至所需大小再进行修改操作。

  3. 减少修改字符串的重分配次数

    • 空间预分配

      如果SDS需要扩展,程序在给SDS分配所需空间后,还会分配额外的未使用空间。

      • 如果修改后len长度小于1MB

        则给SDS分配所需的空间后,再分配同样大小的未使用空间。

        如len长度为1字节,修改后为3字节,则分配2字节空间保证需求,再分配3字节未使用空间进行预分配,下次再进行修改时,如果预分配的3字节够,就不会再进行空间分配操作,而是直接使用,

        此时buf[]的长度为3+3+1,对应的len=3free=3,buf[]={‘1’,‘2’,‘3’,‘\0’,‘’,‘’,‘’},最后就多了3个预分配的空间。

      • 如果修改后len长度大于1MB

        分配满足需求的空间后再额外分配1MB预分配空间。

        如果当前长度为800,修改后的len为1100>1024=1MB,则分配300字节空间满足需求,再分配1MB空间作为预分配空间。此时len=1100+1024+1free=1024

    • 惰性释放

      如果需要缩短字符串,不会立即回收多余的空间,而是用free记录剩余的空间,以备下次扩展时直接使用,避免再次分配。

      如有字符串redis,buf[]={'r','e','d','i','s','\0'},如果只想要red三个字符,则buf结构为:buf[]={‘r’,‘e’,‘d’, ‘ ’ , ‘ ’, ‘\0’ },多余的两个长度的空间不会进行回收,此时使用free=2记录空闲空间。如果再变成redis字符串,则直接在多的空间上进行修改,不会进行空间分配操作。

  4. 二进制安全

可以包含任何数据,包括字符串、序列化对象、图片等,但字符串大小上限为512MB。

二、Key相关命令

因为redis都是以键值对的方式存储,那么和Key有关的命令有哪些呢?

2.1 set

在这里插入图片描述

设置键值对,如果key存在则覆盖旧值。

setnx

这个命令和set有所不同,如果key存在,什么都不做,如果key不存在,则设置key-value

> set name wml
OK
> setnx name wml2
(integer) 0
> get name
"wml"

key存在,不会覆盖旧值

> setnx haha heihei
(integer) 1
> get haha
"heihei"

key不存在,则设置key-value。

可以用于分布式锁。

2.1 查询key

在这里插入图片描述

  • keys 查询所有的键
  • exists key 查询目标key是否存在

type key

键的类型

2.2 查看值

> get name
"wml"

get + key

  • 查看并重置

    > getset name wml2
    "wml"
    > get name
    "wml2"
    
  • 查看指定区间的值

    > getrange name 0 1
    "wm"
    

    可以看到,区间为闭区间

2.3 删除key

> del name
(integer) 1
> keys *
(empty list or set)

2.4 设置查看和清除过期时间

expire和pexpire

直接使用

set name wml ex 50

进行设置,或者分开操作:

> set name wml
OK
> expire name 60 //设置过期时间为60
(integer) 1
> ttl name      //查看还有多久过期(s)
(integer) 56
> pttl name     //查看还有多久过期(ms)
51696
> persist name  //清除过期时间
(integer) 1
> pexpire name2 60000  //设置过期时间(ms),不支持运算
(integer) 1

另外还可以使用setex(s)和psetex(ms)设置过期时间

setex和psetex

> setex address 120 jiangsu
OK
> ttl address
(integer) 108
> psetex address 60000 haha
OK
> ttl address
(integer) 53
  • setex

    设置过期时间,单位s,同时必须指定key和value值

  • psetex

    设置过期时间,单位ms

2.5 追加赋值append

> append age 1
1
> append age 2
2
> get age
"12"

key不存在则直接以追加的值创建新的字符串,如果存在,则将新的字符串追加到旧的后面。

2.6 自增自减

> incr age
(integer) 13
> incr name
(error) ERR value is not an integer or out of range
> decr age
(integer) 12

只能针对整数进行自增1和自减1,否则报错

> incrby age 10
(integer) 22
> decrby age 10
(integer) 12

使用incrbydecrby对指定值为整数的key进行增加和减少指定值。

浮点数处理

如果是浮点类型的,则需要使用incrfloat key value,必须指定增长多少,value可为整数也可以是浮点数,为正是加,为负是减。

> incrbyfloat age2 1
2.2
> incrbyfloat age2 -1
1.2

2.7 批量处理

> mset name1 wml1 name2 wml2 name3 wml3
OK
> mget name1 name2 name4
1) "wml1"
2) "wml2"
3) (nil)

如果key不存在,显示nil

同时可以使用msetnx,和setnx结合,只有在key不存在时才设置键值,但如果批量处理的key中,有一个key存在,则所有的键值对都无法设置成功。(原子性)

> msetnx name1 wml1 name2 wml2 name3 wml3
(integer) 0
> mget name1 name2 name3
1) "wml1"
2) "wml2"
3) "wml3"

所有key都不存在,则批量设置成功。

如果再对存在的key进行msetnx,则都不会设置成功,这里name1和name2存在,因此name4设置失败。

> msetnx name1 wml2 name2 wml4 name4 wml6
(integer) 0
> mget name1 name2 name3
1) "wml1"
2) "wml2"
3) "wml3"
> mget name1 name2 name4 //name4并没有设置成功
1) "wml1"
2) "wml2"
3) (nil)

2.8 修改部分值

> set redis redis
OK
> setrange redis 3 haha
7  //返回新的长度len
> get redis
"redhaha"

可以看到,从下标3开始的位置替换为新的值,此时设置的新的值haha比下标3往后的字符is长,因此全部覆盖。

> setrange redis 10 heihei
16
> get redis
"redhaha\u0000\u0000\u0000heihei"

如果超过了字符串长度,则中间用0填充。

如果修改的长度比剩余的长度小,即只修改第3个位置的字符,后面的会不会消失呢?

> set redis redis
OK
> setrange redis 3 h
5
> get redis
"redhs"

可以看到,如果新的值h小于目标位置后面剩余的字符长度,则只修改目标位置的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值