目录
redis5种数据类型和内部编码方式
redis单线程模型
string字符串类型相关命令
SET
GET
MSET
MGET
SETNX
SETEX
编辑PSETEX
value值为整数,进行加减操作
INCR
INCRBY
DECR
DECRBY
INCRBYFLOAT
APPEND
GETRANGE
SETRANGE
STRLEN
string的内部编码
redis5种数据类型和内部编码方式
redis的5中数据类型如下图所示:
- 字符串类型对应C++ std::string ,java String
- 哈希类型对应C++ std::unordered_map,java中HashMap
- 列表类型对应C++ std::deque ,java List
- 集合类型对应C++ std::set,java Set
- 有序集合存储的时候,除了存储member之外,还需要存储一个权重值
redis中数据类型的内部编码方式根据实际情况而定,比如哈希,背后的实现不一定是一个标准的哈希表,可能在特定的场景下,使用别的数据结构实现,但是仍然保证时间复杂度符合承诺
数据类型 | 内部编码 |
---|---|
string | raw(最基本的字符串,底层就是一个char数组) |
int(value是一个整数的时候,redis可能会用int存) | |
embstr(针对短字符串的优化) | |
hash | hashtable(基本的哈希表) |
ziplist(元素比较少的时候,优化成压缩列表) | |
list | linkedlist(链表) |
ziplist | |
set | hashtable |
intset(集合里都是整数,就优化成intset) | |
zset | skiplist(跳表) |
ziplist |
查看数据类型的内部编码实现方式
object encoding key
上述命令可以查看key对应的value的实际编码方式
redis单线程模型
多个请求同时到达redis服务器,也是要到队列中排队,再等待redis服务器一个一个的取出里面的命令再执行。微观上来讲,redis服务器是串行/顺序执行这多个命令的。
redis是单线程模型,为啥效率这么高呢?速度这么快呢?
首先效率高,速度快的参照物是数据库(mysql、oracle)
- redis访问的是内存,数据库访问的是硬盘
- redis核心功能比数据库的核心功能更简单,比如针对插入删除,数据库有各种约束,都会使数据库做额外的工作。
- 单线程模型,避免了一些不必要的线程竞争开销。
- 处理网络IO的时候,使用了epoll这样的IO多路服用机制,一个线程,就可以管理多个socket
string字符串类型相关命令
redis中的字符串,直接就是按照二进制数据的方式存储的,不会做任何的编码转换,存的是啥,取出来的还是啥。mysql默认的字符集是拉丁文,插入中文会失败。
SET
语法:
SET key value ex 10
等价于
set key value
expire key 10
使用set设置key会存在下述情况:
- 如果key不存在,创建新的键值对
- 如果key存在,则是让新的value覆盖旧的value,可能会改变原来的数据类型,原来的这个key的生存时间也会失效
我们可以通过 NX判断key是否存在,不存在再创建,存在返回nil
xx判断key是否存在,存在才能设置,不存在返回nil
FLUSHALL清空redis里所有键值对
GET
语法:
GET key
对于get来说,只支持字符串类型的value,如果value是其他类型,使用get获取就会出错。
MSET
一次设置多个key的值
语法:
MSET key value [key value ....]
时间复杂度O(n);此处的n是获取key的个数,因此也可以认为是O(1)
示例:
MGET
一次获取多个key的值
语法:
GET key1 key2
时间复杂度O(n);此处的n是获取key的个数
示例:
mget相对于get的优势在于如果一次获取多个key只需要向redis服务器请求一次,而不用请求多次,如下图所示:
SETNX
key不存在才能设置,存在则设置失败
语法:
setnx key value
示例:
SETEX
设置过期时间,单位是秒
语法:
setex key second value
PSETEX
设置过期时间,单位是毫秒
语法:
PSETEX key second value
value值为整数,进行加减操作
INCR
针对value+1
语法:
INCR key
这里的key对应的value必须是整数。
返回值是value+1之后的值。
incr操作的key如果不存在,就会把这个key的value当作0来使用
INCRBY
针对value+n
语法:
INCRBY key
incrby操作的key如果不存在,就会把这个key的value当作0来使用
DECR
针对value-1
DECRBY
针对value-n
INCRBYFLOAT
针对value+/- 小数
由于reids处理命令的时候,是单线程模型,多个客户端同时针对同一个key进行incr的操作也不会引起线程安全的问题.
APPEND
如果key已经存在,并且value是一个string,会将新设置的value追加到原来的string后边,如果不存在,其效果等同于SET命令。
语法:
APPEND KEY VALUE
返回值:追加完成后string的长度,单位是字节。
时间复杂度:O(1);
GETRANGE
返回key对应的string的子串,由start和end确定(左闭右闭),可以使用负数表示倒数,-1表示倒数第一个字符,-2表示倒数第二个字符,其他的与此类似。超过范围的偏移量会根据string的长度调整为正确的值。
语法:
GETRANGE key start end
时间复杂度:O(n);
返回值:取的string子串。
如果字符串中保存的是汉字,此时进行子串切分,很可能切出来,很可能切出来的就不是完整的汉字的。
SETRANGE
覆盖字符串的一部分呢,从指定的偏移开始
语法:
SETRANGE key offset value
- offset是偏移量。
- 当value是一个中文字符串的时候,进行setrange的时候可能会出问题,因为它是按照字节来替换的。
- setrange针对不存在的key也是可以操作的,不过会把offset之前的内容填充成0x00。
时间复杂度:O(1)。
返回值:替换后的string的长度。
示例:
STRLEN
获取字符串的长度,单位是字节。
当key对应的value的类型不是string时报错。
语法:
STRLEN key
时间复杂度:O(1)。
返回值:string的长度,或者当key不存在时,返回0。
string的内部编码
字符串类型的内部编码有3种:
- int:8个字节的长整型。
- embstr:小于等于39个字节的字符串。
- raw:大于39个字节的字符串。
redis会根据当前值的类型和长度动态决定使用哪种内部编码实现。