正规网站建设首选公司,郴州58同城,地方网站做相亲赢利点在哪里,在天猫开店需要什么条件与费用#xff08;一#xff09;数据类型 我们说redis是key value键值对的方式存储数据#xff0c;key是字符串#xff0c;而value是一些数据结构,那今天就来说一下value存储的数据。 我们数据结构包含#xff0c;String#xff0c;hash#xff0c;list#xff0c;set和zest但…一数据类型 我们说redis是key value键值对的方式存储数据key是字符串而value是一些数据结构,那今天就来说一下value存储的数据。 我们数据结构包含Stringhashlistset和zest但是在redis内部真的就是按这些数据结构存储的嘛 很明显上面的图告诉我们不是我们在内部是由不同的内存编码来保存数据的但是时间复杂度是跟我们的数据结构一样的那我们先来看一下第一个
1.String
String数据结构内部编码由rawintembstr
raw存储一些比较短的字符串
int我们redis里没有存储整形数据的方法所以我们一般会用字符串来保存整型数据所以我们String里有一个内存编码int如果我们存入整型数据的话内存编码就是int类型来保存数据。
embstr存储一些比较长的字符串
2.hash
hashtable内部就是一个哈希表
ziplist是一个压缩列表
3.list
内部包含
linkedlist链表不是很节省空间但是效率比较高
ziplist压缩列表比较节省空间但是效率不高
我们redis3.2开始引入了新的实现方式quicklist同时兼顾了linkedlist和ziplist其实quicklist就是个链表每个元素又是一个ziplist同时节省了空间和效率
4.set
hashtable就是一个哈希表
intset集合中存的元素都是整数
5.zset
skiplist跳表也是链表每个节点上有多个指针域使用这些指针域的指向可以做到从跳表上查询的时间复杂度是ologn
查询内部编码方式 使用object encoding key用来查看key对应的value的实际编码方式redis会自动根据实际情况自动适应的 redis单线程模式 我们之前说redis只使用一个线程来处理所有的命令请求但是redis又很快这看起来是相互矛盾的因为多个线程一起执行怎么会比单线程还慢呢 实际上redis确实只有多个线程但是是用来处理网络IO 当我们两个客户端同时发起上述的请求此时我们会产生疑问是否会产生线程安全问题 答案是不会因为我们多个请求同时到达redis服务器需要在队列中排队再等待redis服务器一个一个取出里面的命令再执行类似于实现了一个阻塞队列微观上讲redis服务器是串行执行这个多个命令的 而他快的原因就是因为他的业务逻辑都是些很简单的操作不是很消耗cpu资源但是redis由于是单线程模型就必须要小心某一些操作占用时间太长了阻塞其他命令的执行而且redis是访问内存数据库访问硬盘并且正因为他是单线程模型所以省去了一些线程竞争的开销 处理网络IO的时候是使用了类似epoll这样的IO多路复用机制 这里我们说一下什么是IO多路复用这里我们在网络原理那几篇博客中说过简单来说就是一个线程管理多个socket 我们来回顾一下TCP客户端需要有一个sever socket然后会给我们客户端分配一个socket如果我们多个客户端同时访问同时就有多个socket但这些socket大多数情况下并不是一直都在传输数据很多情况下socket都是静默的因为没有数据要进行传输可能在等待用户的输入但也有一些socket是活跃的我们之前实现的时候因为每个客户端都要分配一个线程客户端多了线程就多了系统开销就会变大所以我们当时有两个方案一个就是引入协程更小的线程一个就是使用IO多路复用 那我们说IO多路复用就是一个线程管理多个socket那对于这些socket也是有要求的我们需要这几个socket交互不频繁大部分时间都在等待如果这几个socket的交互都特别频繁那我们还是要使用多个线程的 二String类型 我们redis中的string是直接按照二进制数据的方式存储的不做任何的编码转换存什么取什么mysql中的默认字符集是拉丁文所以我们插入中文会失败因为是二进制方式存储的所以我们也可以存一些音频和图片等但不可以存太大的
1.set和get 我们看后面的nx和xxnx标识如果key不存在才设置value存在就不设置返回nilxx标识如果key存在那就设置不存在就不设置返回nilex和px是设置过期时间单位是秒和毫秒。 redis文档给出的语法格式说明【】是独立的单元可以同时存在多个【】但是|是表示或一个单元只能出现一个 我们现在库上有很多操作我们可以有一个操作可以删除所有数据就是flushall我们一般不使用
get的使用就很简单但是get只是支持字符串类型的value如果value是其他的类型get就会出错
2.MSET和MGET 这两条命令一次可以操作多组键值对我们之前也说过一次在exists查询多个key时说我们redis是通过网络传输数据的那如果一次传一个数据传多次就会导致我们大部分时间浪费在网络通信中就会导致我们效率变低但是如果我们一次传多个数据就可以很好的节省我们的网络开销 但是还是我们说的那个问题redis是单线程模型如果我们一次性传太多的数据就会导致我们的redis会花很长的时间进行处理就会导致其他的请求等待可能会引发一系列的问题 我们这里的时间复杂度都是O1
3.incr和incrby incr就是针对value的值1我们这里的value必须要是整数如果是小数需要我们是以哦那个incrfloat可以针对小数进行加减操作我们这里的incr操作的key如果不存在我们就会把这个key的value当作0来使用 incrby就是把1操作换成任意的一个整数当然也可以是小数但是这种减法我们会更适用于下一条指令
我们的返回值就是修改后的值
4.decr和decrby 与上条指令类似就是把变成了-我们要注意value中的值必须要是整数在64位范围内如果这个key对应value不存在就会当0处理 decrby就是-n的操作
上述的操作时间复杂度都是o1
5.append字符串拼接 append是用来拼接字符串的返回值是拼接后的长度单位是字节在redis中也是按照utf8进行编码所以一个汉字通常是三个字节 6.setrange设置一定范围的字符
默认从1开始设置但是我们可以设置偏移量 但是如果是一个中文字符串就可能会出问题如果我们凭空生成了一个字节那么就会自动生成一个0x00
返回值是修改后的长度
7.strlen计算value中字符串长度
返回值就是value的长度单位是字节 8.getrange
我们可以设置获取的头和尾通过设置start和end都是闭区间 这里的start和end就类似于下标但是redis下标可以支持负数-1就表示倒数第一个元素如果我们保存的是汉字就会对字符串进行切分到时候就不一定是一个完整的汉字了
9.String的编码方式 我们之前说String内部有三种编码方式并且可以通过object encodingkey来查询内部编码方式那么我们现在就来通过指令来看一下
1int
首先内部编码为int8个字节的长整型
如果我们存的使一个整数那么内部就会变为int但是我们强调必须是整数如果是小数会怎么样
可以看到如果我们的存一个小数内部编码会变为emstr用来存较短的字符串所以整数用int存是方便我们进行算术运算的小数用字符串来存那么我们想要进行运算就需要讲字符串转为小数运算后再保存
2embstr
如果字符串的长度小于某个数内部就会自动编码为emstr具体的数字默认为39 3raw
如果字符串长度比较大内部就会自动编码为raw 10.String的一些应用场景 1缓存功能
这是我们redis作为缓存的模型因为mysql从硬盘读取数据会比较慢但是如果同时有很多请求就会导致mysql出错所以我们引入了redis之前的博客也有详细说到过 那我们String具体在这里有什么用呢我们说key中存的一定是String类型的数据我们先来看一段伪代码
我们让用户传一个id然后我们在内部拼接一个类似报头一样的字符串这样我们就能清楚的知道在redis中这是什么数据如果我们不加我们很可能存在redis中存储了用户的idkey商品的idkey如果统一传来一个id我们也无法知道具体是什么类当然我们也不建议这个名称过长会影响我们redis的一个效率
2计数 我们上面说到内部编码的时候说String可以存整型数据所以我们就可以把redis当作一个计数的基础工具因为redis比较快所以可以用来实现快速计数,查询缓存等功能就比如我们播放一个视频那我们视频的播放量就需要立刻1
但是也有一些问题就是redis不擅长统计数据如果我们要通过value里存的整数来统计一些数据就会比较麻烦就比如我们统计播放量前10的数据如果我们使用mysql直接一个orderby一个limite就可以直接查询到 所以我们需要一个统计数据的仓库可以是mysql也可以是别的来将播放量同步到其他数据源由这个仓库来统计数据这里我们写入统计数据的仓库的方式是异步的也就是说我们不需要获取数据就立刻给这个统计数据的仓库等双方都不是很忙的时候再进行同步就可以
3session
我们在之前的博客里也说到了好几次session他通常跟cookie一起出现
session用来存储服务器数据cookie用来存储客户端数据都是通过键值对的方式存储 我们客户端向服务器发起了请求之后服务器要存储我们的数据就存到了session中然后给我们返回一个token内部可能是sessionid也可以是别的但是一定能通过这个找到对应的session我们客户端通常就会把这个token中的数据存储到cookie中然后我们下次请求服务器的时候就会携带着cookie服务器拿到cookie拿到sessionid然后再获取对应的数据那这个作为标识放到token中的数据就是一个字符串
那这种通过负载均衡分配到不同服务器上的模型如果只是我们上述说的过程就不是很够用了因为我们无法保证每一次访问的都是那一个服务器所以我们需要再引入一个redis
我们通过引入个redis服务器来存储所有session这样我们每个web服务器的session都会放到redis中客户端拿着cookie来查询时我们就会再访问redis寻找对应的session
4手机验证码 我们现在每次登录一个东西会让用户输入手机号并且发送一个验证码通过验证码进行验证确定是不是用户本人但是验证码每多久才可以获取一次并且有过期时间这时我们就可以很好的利用我们的setex key 时间value的指令
我们也可以验证短信把收到的验证码提交系统来进行验证
这是伪代码的实现