哈喽,上节课我们对redis做了一个简单的介绍,这节课我们开始介绍一下redis的数据类型。

简介

首先,Stringredis最基本的数据类型,一个key对应着一个value。翻译成中文来说的话就是字符串类型,这个类型也是我们很常用的一种数据类型。

而这个数据类型是二进制安全的,或许这个意思大家不会太明白,其实这就意味着String类型里面可以包含任何数据,包括图片和视频,因为图片视频是可以序列化成二进制字符串的,那么序列化成了字符串,自然就可以存储进redis中。但是有一个要注意的是redis中的String value最大可以存储512 M

String操作命令

我们对String类型做了简单的介绍,那么这个数据类型怎么使用呢?上节课中我们举了几个例子,我们都是用命令来操作数据库,而就上节课的例子中,用到的其实都是String类型,那么我们来看一下String都有哪些操作命令:

set <key> <value>

这个命令我们也不陌生了,这个命令是往数据库添加键值对,可能有人要问什么是键值对?键值对其实就是key-value。因为key翻译过来就有键的意思。那么key-value便是键值对。

而这个命令通常默认添加到数据库中的数据类型,我们可以看一下:

image-20220424123626112

我们用set命令新增了两个键值对。然后我们看见两个value一个是数字,一个是字母和数字的组合。那么我们也很容易看出k2对应的value是字符串类型,那么k1对应的value又是什么类型呢?我们可以用type命令来查看一下,输出的也是string说明k1对应的value也是字符串类型。

get <key>

既然有set命令,那么对应自然有get命令,这个命令上节课我们也做个简单的介绍,这个命令是获取到指定key所对应value:

image-20220424124955110

我们可以看到我们可以通过get <key>来获取到指定key的值,而输出的值也都是有引号括起来,可见这都是字符串类型的数据。

append <key> <value>

这个命令我们之前没有见到过,这个命令是什么意思呢?

我们先来考虑一个问题,我们用set命令可以新增一个键值对,比如我们set k1 100新增了一个键值对,如果我们再次重新用set命令来对k1进行操作会什么样呢?

image-20220424130057615

我们看见这步操作会直接将指定的key原来的value完全覆盖掉。

append命令则是将指定的value追加到指定key原来value的末尾,并且输出value字符串总长度:

image-20220424130327446

我们看见,k1对应的原来value是 200,然后通过append将 100 追加到原来value的末尾,然后输出了一个数字,这个数字便是k1对应的新的值的长度,然后再用get命令查看k1对应的value发现我们已经将 100 追加到了 200 的末尾。

strlen <key>

这个命令大家应该可以直接猜到,这就是用来查看指定key对应value的长度,我们可以看一下效果:

image-20220424132137260

setnx <key> <value>

这个命令我们之前也没有提到过的,这个命令也是用来新增键值对的,但这个命令是有个特殊的特性,因为这个命令在新增之前会检查key的存在性,只有当key不存在时才会添加成功:

image-20220424133334653

我们来看一下,现在库里有k1k2这两个key,那么我们用setnx命令对k1重新设置value,然后输出了一个数字 0,我们上节课也提到过了,这是代表是否成功,既然输出 0,那么说明这次操作是失败的。

然后我们用get命令来看一下k1的值,我们发现,并没有被修改,也正是证明了setnx无法对已存在的key进行修改操作。那么我们再来看用setnx新增一个k3

输出了 1,说明新增成功,再用get命令来查看一下k3的值,输出的正是我们指定的value

incr / decr <key>

这两个命令是缩写,分别对应incrementdecrement,这两个命令的用处便是让指定key对应value值的数字加 1 或者减 1:

image-20220424135535266

我们来看一下k3原有的value是 500,然后执行incr命令,使得k3value加 1,输出的便是修改后的k3对应的value。然后执行decr命令之后也是一样。

而这些命令都是原子操作。那么什么是原子操作呢?所谓原子操作是指不会被线程调度机制打断的操作,一旦开始,就一定会运行到结束。在单线程中能够在单条命令中完成的操作都可以认为是原子操作。而在多线程中不能被其他线程或进程打断的操作都是原子操作。

incrby / decrby <key> <步长>

这两个命令和之前看见的incr / decr看着很想,当然这两个命令呢也是让指定key对应value的数字值加上或者减去指定的值。为啥这里说的是指定值呢?因为我们看见这个命令除了key之外还有一个所谓“步长”的参数。那么这个步长是什么意思呢?

这个步长就是指我们说的指定的值。我们来看一下是什么效果:

image-20220424140853936

我们来看k3原来的value是 500,然后执行incrby命令,然后将步长设为 50,这就代表了将k3对应的value加上 50,然后输出的便是k3加上步长之后的的值,然后再执行decrby命令,将步长设为 20,代表将k3对应的value减去 20。并输出计算后的值。

mset <key1> <value1> <key2> <value2>...

这个命令可以添加多个键值对,用法和set命令近似,我们就不再赘述了。

mget <key1> <key2>...

这个命令可以获取多个keyvalue,用法与get命令近似,我们也就不再赘述了。

msetnx <key1> <value1> <key2> <value2>...

该命令与setnx命令近似,当所添加的所有key都不存在时,便添加所有键值对到库里。该命令具有原子性。该命令设置的key中有一个无法成功添加,整个命令都会失败。

getrange <key> <起始位置> <结束位置>

这个命令可以获取指定keyvalue的某一段值,怎么解释呢?语言从来都是苍白无力的。我们来看一下示例:

image-20220424142908971

我们来看一下,我们执行getrange命令,传入的起始位置和结束位置分别为 0 和 3。这个 0 和 3 又是什么意思呢?这个就是所谓的索引,计算机中的索引通常都是从 0 开始计数,起始位置为 0,那么就代表从左往右数第 1 位,结束位置为 3,代表从左往右数第 4 位。

整个命令便是获取到k3对应value的第 1 位到第 4 位的片段。输出的便是abcd

setrange <key> <起始位置> <value>

该命令从指定keyvalue的指定位置开始修改value值。我们来看一下:

image-20220424144537207

我们执行了setrange命令,起始位置设置为 3,也就代表从k1对应value值的第 4 位开始修改,然后输出的便是修改后的value的长度。然后执行get命令,我们看见从第 4 位开始往后便改成了我们指定的value

setex <key> <过期时间> <value>

这个命令用于添加键值对,并设置过期时间,我们之前可以利用set命令新增键值对,然后用expire命令给key设置过期时间。但是setex命令可以直接在新增键值对的时候可以直接设置过期时间。

image-20220424145853712

我们可以从图中看出该命令的用法,然后可以用ttl命令查看key的过期时间。

getset <key> <value>

这个命令在给指定key设置新值的同时获取到该key原来的值:

image-20220424150654863

我们看见k1原来的valuev200,然后执行getset命令,输出了k1对应的原来的value,那么我们再执行get命令,发现k1对应的value已经被修改了。

以上便是String类型的常用命令。

String数据结构

我们介绍了String类型的常用命令,那么我们来介绍一下String的数据结构。

String类型是简单的动态字符串,底层来说内部结构类似于javaArrayList,通过预分配冗余空间来减少内存频繁分配:

\overset{|\leftarrow------------------------\ \ \ \ \ capacity\ \ \ \ \ -----------------------\rightarrow|}{ \underset{|\leftarrow-------------\ \ \ \ \ \ \ len\ \ \ \ \ \ -------------\rightarrow|}{ \boxed{\begin{matrix}\ & \ & \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \ \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \ \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}} \boxed{\begin{matrix}\ & \ & \\ \end{matrix}}}

我们来看一下底层的内存分配情况,其实每一个字符串再内存中存储时开辟的空间为capacity,而capacity是要大于字符串长度的,如果存储字符串继续增长,那么就要对存储空间进行扩容。

如果字符串大小小于1 M,那么每次扩容将会以capacity为单位,每次扩容将扩充一个单位。

如果字符串大小大于1 M,那么每次扩容将只扩充1 M的空间。

总结

  • String类型为redis最基础的类型
  • String常用命令:
    • set <key> <value>
    • get <key>
    • append <key> <value>
    • strlen <key>
    • setnx <key> <value>
    • incr / decr <key>
    • incrby / decrby <key> <步长>
    • mset <key1> <value1> <key2> <value2>...
    • mget <key1> <key2>...
    • msetnx <key1> <value1> <key2> <value2>...
    • getrange <key> <起始位置> <结束位置>
    • setrange <key> <起始位置> <value>
    • setex <key> <过期时间> <value>
    • getset <key> <value>
  • String是动态字符串
  • 通过分配冗余空间减少内存频繁分配
  • 字符串会动态对空间进行扩展

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/redis-datatype_string/