国外创意网站设计欣赏,推广赚钱的软件排行,微信小程序项目开发实战,销售管理软件crm初识Redis缓存
Redis缓存#xff1a;
实际开发中经常使用Redis作为缓存数据库#xff0c;从而提高数据存取效率#xff0c;减轻后端数据库的压力。
可以将经常被查询的数据缓存起来#xff0c;比如热点数据#xff0c;这样当用户来访问的时候#xff0c;就不需要到MyS…初识Redis缓存
Redis缓存
实际开发中经常使用Redis作为缓存数据库从而提高数据存取效率减轻后端数据库的压力。
可以将经常被查询的数据缓存起来比如热点数据这样当用户来访问的时候就不需要到MySQL中去查询了而是直接获取Redis中的缓存数据。
Redis是键值对类型的数据库在设计数据时都要指定key和value。
例如某查询系统可以根据提供的网站名称返回相应的网址因为查询的系统的并发量较高此时可以将上述的对应关系通过Redis缓存到内存中。
设置网站名称baidu到网址http://www.baidu.com的对应关系名称作为key网址作为value 取出缓存用户输入名称数据库就可以把对应网址取出来了 设置缓存的时间
实际项目里一般需要同时设置数据的生存时间。如果不设置那么内存里的数据会越积越多最终造成内存溢出。
可以在命令后通过ex或px参数设置该对象的生存时间其中ex的时间单位是秒px的时间单位是毫秒如 设置了val1对象的生存时间是2秒当过了对应的时间用get命令去获取对象的值时只能得到表示空的null值。 Redis数据类型
Redis为了存储不同类型的数据提供了五种常用数据类型
string (字符串)hash (哈希散列)list (列表)set (集合)zset (sorted set有序集合)
注意此处的数据类型指的是Value值的数据类型而非key。
基本数据类型String
SDS:
字符串是Redis里最基本的数据类型Redis使用标准C语言编写但在存储字符时Redis并未使用C语言的字符类型。
而是自定义了一个属于特殊结构SDS(Simple Dynamic String)即简单动态字符串)。【可以理解为用C的结构体实现了一个String类型】
SDS是一个可以修改的内部结构非常类似于Java的ArrayList。
SDS的结构定义如下 String类型的空间分配方式
string采用了预先分配冗余空间的方式来减少内存的频繁分配如下图所示
(总体空间即上图char buf[]的空间 ) Redis每次给string分配的空间都要大于字符串实际占用的空间这样就在一定程度上提升了Redis string存储的效率比如当字符串长度变大时无需再重新申请内存空间。
当字符串所占空间小于1MB时Redis对字符串存储空间的扩容是以成倍的方式增加的而当所占空间超过1MB时每次扩容只增加1MB。Redis字符串允许的最大值字节数是512MB。
String类型的使用
字符串是Redis里最基本的数据类型。 可以使用set命令设置字符串类型数据具体语法如下
set key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
key和value分别表示待设置字符串的键和值如果对应的key里已经有值那么再次执行set命令时会进行覆盖。value就是String类型。[]中为可选内容
通过EX和PX参数可以指定该变量的生存时间在大多数场景里应该合理设置对应的生存时间否则可能会导致内存溢出的问题。
NX参数表示当key不存在时才进行设置值的操作如果key存在那么该命令执行XX参数表示当key存在时才进行操作。
KEEPTTL是Redis6.0的新特性是指保留生存时间”既重复set时保留值的过期时间。
设置以后可以通过get key的方式读取对应key的字符串变量具体示例 设置获取单个字符串
缓存员工号002、姓名Tom的数据 设置获取多个字符串
mset和mget命令分别能同时设置和获取多个字符串。
其中mset命令的语法mset key value [key value...]
mget命令的语法mget key [key...]
mset和mget命令不包含NX、XX、PX和EX等参数。
示例
ttl -1 代表永久有效 对值进行增量和减量操作
通过incr key命令能对key所对应的数字类型值进行加1操作如果k不存在默认在0的基础上1
通过decr key命令能对key所对应的值进行减1操作如果k不存在默认在0的基础上-1
通过incrby key increment命令能对key对应的值进行加lincrement的操作
通过decrby by decrement命令能对key对应的值进行减decrement的操作
incr和decr命令作用在字符类型上会出错
运行上述命令时需要确保key对应的值是数字类型否侧会报错。在实际项目里上述命令一般会用在统计流量和控制并发的场景中 通过getset命令设置新值
getset key value
如果key对应的值存在则会用value覆盖旧值同时返回旧值set可以覆盖但不会返回旧值
如果key对应的值不存在也会设值但会返回null 基本数据类型Hash
Hash类型
Redis hash(哈希散列)是由字符类型的field(字段)和value组成的哈希映射表结构也称散列表
【redis的键值对映射则指的是整体数据】
hash类型中field与value一一对应且不允许重复。
Redis hash特别适合于存储对象。一个filed/value可以看做是表格中一条数据记录而一个key可以对应多条数据多个字段和value的组合。
当hash类型移除最后一个元素后该存储结构就会被自动删除其占用内存也会被系统回收。
Hash类型底层存储结构的实现方式(2种)
第一种当存储的数据量较少时hash采用ziplist(压缩列表内存中一块连续的存储空间)作为底层存储结构此时要求符合以下两个条件
1哈希对象保存的所有键值对键和值的字符串长度总和小于64个字节。 2哈希对象保存的键值对数量要小于512个。
当无法满足上述条件时hash就会采用第二种方式来存储数据
也就是dict(字典结构)该结构类似于Java的HashMap是一个无序的字典并采用了数组和链表相结合的方式存储数据。
在Redis中dict是基于哈希表算法实现的因此其查找性能非常高效其时间复杂度为O(1)。
哈希表
哈希表又称散列表其初衷是将数据映射到数组中的某个位置上 这样就能够通过数组下标来访问该数据从而提高数组的查询效率。
现在有1/5/8/ 三个数字你需要把这三个数字映射到数组中由于哈希表规定必须使用下标来访问数据因此你需要构建一个0到8的数组 普通查找把待查找的数字在相应的下标数组上标记出来它们之间一一对应。虽然这样能查但很浪费存储空间并且查找效率也不高。
如果采用哈希表的话我们只需要申请一个长度为3的数组与待查找的元素个数相同)如下图所示 将1/5/8分别对数组长度3做取模运算然后把它们指向运算结果对应的数组槽位这样就把一组离散的数据映射到了连续的空间中从而在最大限度上提高了空间的利用率并且也提高了元素的查找效率。
但可能会出现一个问题数字5、8映射到同一个槽位上这样就导致其中一个数字无法查找到。上述这种情况在实际中也会遇到我们把它称为“哈希冲突”或者“哈希碰撞”。
解决哈希冲突
有许多方法可以解决“哈希冲突”比如开放地址法、链表地址法再次散列法等而Redis采用是链表地址法。
将有冲突的数据使用链表把它们串联起来这样即使发生了冲突也可以将数据存储在一起最后通过遍历链表的方式就找到上述发生“冲突”的数据。 如下所示 如果值是字符串的话就需要通过哈希函数将字符串转换成具体的数值然后再对其进行映射。
设置与获取hset和hget
哈希类型可以通过hset命令来设置数据通过hget命令来读取数据。
hset的命令格式如下
hset key field value [field value ...]
其中key是待缓存对象的键field value是以键值对的形式描述的对象数据。
针对同一个key,可以用多个field value对来存储数据这里field可以理解成对象的属性名value可以理解成对象的属性值。
hget的命令格式如下其中key是待读取对象的键如果存在key和field所对应的数据则返回该数据否则返回null值。仅传入key而不传入field参数会报错。
hget key field
示例 hsetnx命令
用hset命令设置哈希类型的变量时如果出现重复就会用后设的数据覆盖掉之前的数据。
与之对应的是hsetnx命令
hsetnx key field value
只有当key和field所对应的value不存在时才会设置对应的value,而且key之后只能带一对field和value
hset命令的key之后能带多个field和value对。
针对key的相关操作
通过hkeys key命令能查看该key所对应哈希类型数据的所有field; 通过hvals key命令能查看key所对应哈希类型数据的所有value; 通过hgetall key命令能以field和value对的形式查看key对应的哈希类型数据。 hexists命令
通过hexists命令能判断key和field对应的value是否存在。
hexists命令的格式
hexists key field对哈希类型数据的删除操作:
通过hdel命令能删除key指定的field数据该命令的格式如下
hdel key field [field...]
通过该命令能同时删除一个key对应的多个field数据。如果要删除指定key所对应的整个哈希类型的数据则需要用del key命令。 基本数据类型List
Redis list(列表)相当于Java语言中的LinkedList结构是一个链表而非数组其插入、删除元素的时间复杂度为O(1),但是查询速度欠佳时间复杂度为O(n)。
当向列表中添加元素值时首先需要给这个列表指定一个key键然后使用相应的命令从列表的左侧头部或者右侧尾部来添加元素这些元素会以添加时的顺序排列。
当列表弹出pop最后一个元素时该结构会被自动删除。
Redis列表的底层存储结构其实是一个被称为快速链表(quicklist)的结构。
当列表中存储的元素较少时
Redis 使用一块连续的内存来存储这些元素这个连续的结构被称为ziplist(压缩列表)它将所有的元素紧挨着一起存储。使用压缩列表来做列表的底层实现的情况 1 当一个列表只包含少量列表项并且每个列表项要么就是小整数值要么就是长度比较短的字符串 2当一个哈希只包含少量键值对比且每个键值对的键和值要么就是小整数值要么就是长度比较短的字符串
压缩列表是Redis为了节约内存而开发的是由一系列特殊编码的连续内存块组成的顺序型(sequential))数据结构。
一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值。
当列表中存储的元素较多时
Redis列表用quicklist(快速链表)存储元素。
Redis之所以采用两种方法相结合的方式来存储元素这是因为单独使用普通链表存储元素时所需的空间较大会造成存储空间的浪费。因此采用了链表和压缩列表相结合的方式也就是quicklistziplist,结构如下图 将多个ziplist使用双向指针串联起来这样既能满足快速插入、删除的特性又节省了一部分存储空间。
设置与获取
可以通过lpush命令把一个或多个值依次且一次性插入到列表的头部因此读取索引号是0的数据时返回的是最后插入的数据。
key指定待插入的列表element表示插入到列表的值。
lpush key element [element ...]
也可以用rpush命令在指定列表的尾部插入数据该命令格式如下
rpush key element [element ...]
可以通过lindex命令读取列表的值key指定待读取的列表index指定待读取列表值的索引号。注意索引号是从0开始的。
lindex key index
示例 模拟堆栈和队列
lpush向左边(list头)添加数据。rpush向右边(list尾)添加数据
与之对应的有lpop和rpop命令表示分别从Iist头和list尾读数据而且读完会把该数据从列表里弹出移除。
通过如下的lpush和lpop命令能模拟先入后出”的堆栈效果 还可以通过lpush和rpop命令来模拟“先来先服务”的队列效果
lrange:
通过lrange命令可以获取指定区间内的数据start和stop分别表示开始索引和结束索引。
该命令的格式
lrange key start stop start stop时才会取出数据。负数则表示倒数第几个。 获取列表包含的所有元素
快捷方法使用0作为起始索引、-1作为结束索引去调用lrange命令这种方法非常适合于查看长度较短的列表。
列表中的最后一个元素索引为-1依次类推。 修改列表中的元素
通过lset命令能修改列表里的元素能把由key指定的列表里index的数据修改为element。
该命令的格式
lset key index element 将元素插入列表
通过使用linsert命令用户可以将一个新元素插入列表某个指定元素的前面或者后面
linsert list BEFORE|AFTER target_element new_element
linsert命令第二个参数的值可以是before或after它们分别用于指示命令将新元素插入目标元素的前面或后面 获取列表的长度
用户可以通过执行llen命令来获取列表的长度即列表包含的元素数量
llen list 移除指定的元素
可以通过lrem命令删除列表里的指定元素该命令的格式如下
lrem key count element
当count 0时删除该列表里所有值是element的数据
当count 0时删除从头到尾方向数量为count个、值是element的数据(从左往右删除)
当count 0时删除从尾到头方向数量为count个、值是element的数据。(从右往左删除) 修剪列表
ltrim命令接受一个列表和一个索引范围作为参数并移出列表中位于给定索引范围之外的所有元素只保留给定范围之内的元素
LTRIM list start end
LTRM命令在执行完移除操作之后将返回OK作为结果。 基本数据类型Set
Set类型
Redis的集合(set)键允许用户将任意多个各不相同的元素存储到集合中这些元素既可以是文本数据也可以是二进制数据。
虽然都可以存储多个元素但集合与列表有以下两个明显的区别 1列表可以存储重复元素而集合只会存储非重复元素尝试将一个已存在的元素添加到集合将被忽略。
2列表以有序方式存储元素而集合则以无序方式存储元素。
这两个区别带来的差异主要跟命令的复杂度有关
在执行像LINSERT和LREM这样的列表命令时即使命令只针对单个列表元素程序有时也不得不遍历整个列表以确定指定的元素是否存在因此这些命令的复杂度都为O(N)。
对于集合来说因为所有针对单个元素的集合命令都不需要遍历整个集合所以复杂度都为O(1)。
因此当我们需要存储多个元素时就可以考虑这些元素是否可以以无序的方式存储并且是否不会出现重复。如果是那么就可以使用集合来存储这些元素从而有效地利用集合操作的效率优势。
将新元素添加到集合中
使用sadd命令将一个或多个元素添加到集合中命令格式如下
sadd set element [element ...]
用sadd添加元素时会自动忽略已存在的元素只将不存在于集合的新元素添加到集合中。 集合中移除已有的元素
使用srem命令将一个或多个元素从集合中移除
srem set element [element ...]
这个命令会返回被移除的元素数量 将指定的元素从一个集合移动到另一个集合
smove命令允许用户将指定的元素从源集合移动到目标集合
smove source target element
smove命令在移动操作成功执行时返回1。如果指定的元素并不存在于源集合那么smove命令将返回0表示移动操作执行失败。 获取集合包含的所有元素
通过使用smembers命令用户可以取得集合包含的所有元素
smembers set 因为Redis集合以无序的方式存储元素并且SMEMBERS命令在获取集合元素时也不会对元素进行任何排序动作所以根据元素添加顺序的不同2个包含相同元素的集合在执行SMEMBERS命令时的结果也可能会有所不同。
获取集合包含的元素数量
通过scard命令用户可以获取给定集合的大小即集合包含的元素数量
scard set 检查给定元素是否存在于集合中
使用sismember命令
sismember set element 从集合中随机地获取指定数量的元素
通过使用SRANDMEMBER命令用户可以从集合中随机地获取指定数量的元素。
SRANDMEMBER命令接受一个可选的count参数用于指定用户想要获取的元素数量如果用户没有给定这个参数那么SRANDMEMBER命令默认只获取一个元素
SRANDMEMBER set [count]
被SRANDMEMBER命令返回的元素仍然会存在于集合当中。
若count参数的值为正数SRANDMEMBER命令将返回count个不重复的元素。
若count参数的值为负数SRANDMEMBER命令将随机返回abs(count)个元素并且在这些元素当中允许出现重复的元素。 随机从集合中移除指定数量的元素
SPOP命令接受一个可选的cout参数用于指定需要被移除的元素数量。如果用户没有给定这个参数那么SPOP命令默认只移除一个元素
spop key [count]
SPOP命令只接受正数count值如果向SPOP命令提供负数count值将引发错误因为负数count值对于SPOP命令是没有意义的 集合运算
sinter命令可以计算用户给定的所有集合的交集然后返回这个交集包含的所有元素
sinter set [set..,]
sunion命令可以计算出用户给定的所有集合的并集然后返回这个并集包含的所有元素
sunion set [set..,]
sdiff命令可以计算出给定集合之间的差集并返回差集包含的所有元素
sdiff set [set..,]
有序集合
Redis的有序集合(sorted set)同时具有“有序”和“集合”两种性质。
这种数据结构中的每个元素都由一个成员和一个与成员相关联的分值组成其中成员以字符串方式存储而分值则以64位双精度浮点数格式存储。
与集合一样有序集合中的每个成员都是独一无二的同一个有序集合中不会出现重复的成员。有序集合的成员将按照它们各自的分值大小进行排序比如分值为3.14的成员将小于分值为10.24的成员而分值为999的成员也会小于分值为10086的成员。
有序集合的分值除了可以是数字之外还可以是字符串 inf 或者 -inf ,这两个特殊值分别用于表示无穷大和无穷小。
同一个有序集合不能存储相同的成员但不同成员的分值却可以是相同的。
当两个或多个成员拥有相同的分值时Rdis将按照这些成员在字典序中的大小对其进行排列
举个例子如果成员apple和成员zero都拥有相同的分值100那么Redis将认为成员apple小于成员zero,这是因为在字典序中字母a开头的单词要小于字母z开头的单词。
有序集合是Redis提供的所有数据结构中最为灵活的一种它可以以多种不同的方式获取数据比如根据成员获取分值、根据分值获取成员、根据成员的排名获取成员、根据指定的分值范围获取多个成员等。
有序集合_添加或更新成员
使用ZADD命令用户可以向有序集合添加一个或多个新成员
zadd sorted_set score member [score member ...]
ZADD命令除了可以向有序集合添加新成员之外还可以对有序集合中已存在成员的分值进行更新 在默认情况下如果用户在执行ZADD命令时给定成员已经存在于有序集合中并且给定的分值和成员现有的分值并不相同那么ZADD命令将使用给定的新分值去覆盖现有的旧分值。 有序集合_移除指定的成员
通过使用ZREM命令用户可以从有序集合中移除指定的一个或多个成员以及与这些成员相关联的分值
zrem sorted_set member [member...]
通过使用ZSCORE命令用户可以获取与给定成员相关联的分值
zscore sorted_set member 有序集合_对成员分值执行自增或自减操作
使用ZINCRBY命令对有序集合中指定成员的分值执行自增操作为其加上指定的增量。
zincrby sorted_set increment member
redis没有相应的自减操作所以可以将一个负数增量传给ZINCRBY命令达到对分值的自减操作。
有序集合_获取成员在有序集合中的排名
排名标记是从0开始的。
ZRANK命令返回的是成员的升序排列排名即成员在按照分值从小到大进行排列时的排名
ZRANK sorted_set member
ZREVRANK命令返回的则是成员的降序排列排名即成员在按照分值从大到小进行排列时的排名。
ZREVRANK sorted_set member 有序集合_获取指定索引范围内的成员
排名标记是从0开始的。
ZRANGE命令返回的是在索引范围内成员的升序排列排名即成员在按照分值从小到大进行排列时的排名
zrange sorted_set start end
ZREVRANGE命令返回的则是在索引范围内成员的降序排列排名即成员在按照分值从大到小进行排列时的排名。
zrevrange sorted_set start end 有序集合_获取指定分值范围内的成员
ZRANGEBYSCORE以升序排列的方式获取有序集合中分值介于指定范围内的成员
ZRANGEBYSCORE sorted_set min max
ZREVRANGEBYSCORE以降序排列的方式获取有序集合中分值介于指定范围内的成员
ZREVRANGEBYSCORE sorted_set max min
命令的min参数和max参数分别用于指定用户想要获取的成员的最小分值和最大分值
ZRANGEBYSCORE命令和ZREVRANGEBYSCORE命令接受min参数和max参数的顺序正好相反。 有序集合_统计指定分值范围内的成员数量
使用ZCOUNT命令可以统计出有序集合中分值介于指定范围之内的成员数量
zcount sorted_set min max 范围控制
ZRANGEBYSCORE、ZCOUNT等命令可以控制区间的开合。上述命令接受的分值范围都是闭区间分值范围。
如果用户想要定义的是开区间而不是闭区间那么可以在给定分值范围时在分值参数的前面加上一个单括号“(”这样具有给定分值的成员就不会出现在命令返回的结果当中。
min参数和max参数除了可以是普通的分值或者带有符号的分值之外还可以是特殊值inf或者-inf。前者用于表示无穷大而后者则用于表示无穷小。